@bablr/agast-vm-helpers 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/builders.js +35 -36
- package/lib/deembed.js +17 -0
- package/lib/embed.js +21 -0
- package/lib/index.js +19 -19
- package/lib/internal-builders.js +1 -0
- package/package.json +6 -3
package/lib/builders.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
interpolateArrayChildren,
|
|
5
5
|
interpolateString,
|
|
6
6
|
} from '@bablr/agast-helpers/template';
|
|
7
|
+
import { isNull } from '@bablr/agast-helpers/tree';
|
|
7
8
|
import * as t from '@bablr/agast-helpers/shorthand';
|
|
8
9
|
import * as l from './languages.js';
|
|
9
10
|
|
|
@@ -26,7 +27,7 @@ export const buildReference = (name, isArray) => {
|
|
|
26
27
|
[t.ref`name`, ...when(isArray, [t.ref`arrayOperatorToken`]), t.ref`sigilToken`],
|
|
27
28
|
{
|
|
28
29
|
name: buildIdentifier(name),
|
|
29
|
-
arrayOperatorToken: isArray ? t.s_node(l.CSTML, 'Punctuator', '[]') :
|
|
30
|
+
arrayOperatorToken: isArray ? t.s_node(l.CSTML, 'Punctuator', '[]') : t.null_node(),
|
|
30
31
|
sigilToken: t.s_node(l.CSTML, 'Punctuator', ':'),
|
|
31
32
|
},
|
|
32
33
|
);
|
|
@@ -60,11 +61,11 @@ export const buildFlags = (flags = {}) => {
|
|
|
60
61
|
...when(expression, [t.ref`expressionToken`]),
|
|
61
62
|
],
|
|
62
63
|
properties: {
|
|
63
|
-
triviaToken: trivia
|
|
64
|
-
intrinsicToken: intrinsic
|
|
65
|
-
tokenToken: token
|
|
66
|
-
escapeToken: escape
|
|
67
|
-
expressionToken: expression
|
|
64
|
+
triviaToken: trivia ? t.s_node(l.CSTML, 'Punctuator', '#') : t.null_node(),
|
|
65
|
+
intrinsicToken: intrinsic ? t.s_node(l.CSTML, 'Punctuator', '~') : t.null_node(),
|
|
66
|
+
tokenToken: token ? t.s_node(l.CSTML, 'Punctuator', '*') : t.null_node(),
|
|
67
|
+
escapeToken: escape ? t.s_node(l.CSTML, 'Punctuator', '@') : t.null_node(),
|
|
68
|
+
expressionToken: expression ? t.s_node(l.CSTML, 'Punctuator', '+') : t.null_node(),
|
|
68
69
|
},
|
|
69
70
|
};
|
|
70
71
|
};
|
|
@@ -82,9 +83,15 @@ export const buildFullyQualifiedSpamMatcher = (
|
|
|
82
83
|
) => {
|
|
83
84
|
const attributes_ = buildAttributes(attributes);
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
let language_;
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
if (isString(language)) {
|
|
89
|
+
language_ = language;
|
|
90
|
+
} else {
|
|
91
|
+
let lArr = isString(language) ? language : language ? [...language] : [];
|
|
92
|
+
|
|
93
|
+
language_ = lArr.length === 0 ? null : lArr;
|
|
94
|
+
}
|
|
88
95
|
|
|
89
96
|
return t.node(
|
|
90
97
|
l.Spamex,
|
|
@@ -102,23 +109,17 @@ export const buildFullyQualifiedSpamMatcher = (
|
|
|
102
109
|
{
|
|
103
110
|
openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
|
|
104
111
|
flags: buildFlags(flags),
|
|
105
|
-
language: buildLanguage(language_),
|
|
106
|
-
languageSeparator: language_ && type
|
|
107
|
-
type: type
|
|
108
|
-
intrinsicValue: intrinsicValue
|
|
112
|
+
language: language_ ? buildLanguage(language_) : t.null_node(),
|
|
113
|
+
languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
|
|
114
|
+
type: type ? buildIdentifier(type) : t.null_node(),
|
|
115
|
+
intrinsicValue: intrinsicValue ? buildString(intrinsicValue) : t.null_node(),
|
|
109
116
|
attributes: attributes_,
|
|
110
117
|
closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
|
|
111
118
|
},
|
|
112
119
|
);
|
|
113
120
|
};
|
|
114
121
|
|
|
115
|
-
export const buildNodeOpenTag = (
|
|
116
|
-
flags,
|
|
117
|
-
language,
|
|
118
|
-
type = null,
|
|
119
|
-
intrinsicValue = null,
|
|
120
|
-
attributes = {},
|
|
121
|
-
) => {
|
|
122
|
+
export const buildNodeOpenTag = (flags, language, type = null, attributes = {}) => {
|
|
122
123
|
const attributes_ = buildAttributes(attributes);
|
|
123
124
|
|
|
124
125
|
let language_ = !language || language.length === 0 ? null : language;
|
|
@@ -131,21 +132,17 @@ export const buildNodeOpenTag = (
|
|
|
131
132
|
t.ref`flags`,
|
|
132
133
|
...when(language_, [t.ref`language`, t.ref`languageSeparator`]),
|
|
133
134
|
...when(type, [t.ref`type`]),
|
|
134
|
-
...when(intrinsicValue, [t.embedded(buildSpace()), t.ref`intrinsicValue`]),
|
|
135
135
|
...when(attributes_.length, [t.embedded(buildSpace())]),
|
|
136
136
|
...interpolateArrayChildren(attributes_, t.ref`attributes[]`, t.embedded(buildSpace())),
|
|
137
|
-
when(intrinsicValue, [t.embedded(buildSpace), t.ref`selfClosingToken`]),
|
|
138
137
|
t.ref`closeToken`,
|
|
139
138
|
],
|
|
140
139
|
{
|
|
141
140
|
openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
|
|
142
141
|
flags: buildFlags(flags),
|
|
143
|
-
language: buildLanguage(language_),
|
|
144
|
-
languageSeparator: language_ && type
|
|
145
|
-
type: type
|
|
146
|
-
intrinsicValue: intrinsicValue && buildString(intrinsicValue),
|
|
142
|
+
language: language_ && type ? buildLanguage(language_) : t.null_node(),
|
|
143
|
+
languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
|
|
144
|
+
type: type ? buildIdentifier(type) : t.null_node(),
|
|
147
145
|
attributes: attributes_,
|
|
148
|
-
selfClosingToken: intrinsicValue && t.s_node(l.CSTML, 'Punctuator', '/'),
|
|
149
146
|
closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
|
|
150
147
|
},
|
|
151
148
|
);
|
|
@@ -178,7 +175,7 @@ export const buildDoctypeTag = (attributes) => {
|
|
|
178
175
|
};
|
|
179
176
|
|
|
180
177
|
export const buildIdentifierPath = (path) => {
|
|
181
|
-
const path_ = [...path];
|
|
178
|
+
const path_ = isString(path) ? [path] : [...path];
|
|
182
179
|
const segments = path_.map((name) => buildIdentifier(name));
|
|
183
180
|
const separators = path_.slice(0, -1).map((_) => t.s_node(l.CSTML, 'Punctuator', '.'));
|
|
184
181
|
|
|
@@ -198,7 +195,9 @@ export const buildIdentifierPath = (path) => {
|
|
|
198
195
|
};
|
|
199
196
|
|
|
200
197
|
export const buildLanguage = (language) => {
|
|
201
|
-
return language &&
|
|
198
|
+
return language && isString(language) && language.startsWith('https://')
|
|
199
|
+
? buildString(language)
|
|
200
|
+
: buildIdentifierPath(language);
|
|
202
201
|
};
|
|
203
202
|
|
|
204
203
|
export const buildNodeCloseTag = (type, language) => {
|
|
@@ -214,9 +213,9 @@ export const buildNodeCloseTag = (type, language) => {
|
|
|
214
213
|
],
|
|
215
214
|
{
|
|
216
215
|
openToken: t.s_node(l.CSTML, 'Punctuator', '</'),
|
|
217
|
-
language: buildLanguage(language),
|
|
218
|
-
languageSeparator: language && type ? t.s_node(l.CSTML, 'Punctuator', ':') :
|
|
219
|
-
type: type
|
|
216
|
+
language: language ? buildLanguage(language) : t.null_node(),
|
|
217
|
+
languageSeparator: language && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
|
|
218
|
+
type: type ? buildIdentifier(type) : t.null_node(),
|
|
220
219
|
closeToken: t.s_node(l.CSTML, 'Punctuator', '>'),
|
|
221
220
|
},
|
|
222
221
|
);
|
|
@@ -354,7 +353,7 @@ export const buildString = (value) => {
|
|
|
354
353
|
if (escapables[chr]) {
|
|
355
354
|
value = t.node(l.CSTML, 'EscapeCode', [t.ref`sigilToken`], {
|
|
356
355
|
sigilToken: buildKeyword(escapables[chr]),
|
|
357
|
-
digits:
|
|
356
|
+
digits: t.null_node(),
|
|
358
357
|
});
|
|
359
358
|
} else if (chr.charCodeAt(0) < 32) {
|
|
360
359
|
const hexDigits = chr.charCodeAt(0).toString(16).padStart(4, '0');
|
|
@@ -372,7 +371,7 @@ export const buildString = (value) => {
|
|
|
372
371
|
}
|
|
373
372
|
|
|
374
373
|
terminals.push(
|
|
375
|
-
t.
|
|
374
|
+
t.buildEmbeddedNode(
|
|
376
375
|
t.e_node(
|
|
377
376
|
l.CSTML,
|
|
378
377
|
'EscapeSequence',
|
|
@@ -509,7 +508,7 @@ export const buildMappingAttribute = (key, value) => {
|
|
|
509
508
|
|
|
510
509
|
export const buildBooleanAttribute = (key, value) => {
|
|
511
510
|
return t.node(l.CSTML, 'BooleanAttribute', [...when(!value, [t.ref`negateToken`]), t.ref`key`], {
|
|
512
|
-
negateToken: !value ? t.s_node(l.CSTML, 'Puncutator', '!') :
|
|
511
|
+
negateToken: !value ? t.s_node(l.CSTML, 'Puncutator', '!') : t.null_node(),
|
|
513
512
|
key: buildIdentifier(key),
|
|
514
513
|
});
|
|
515
514
|
};
|
|
@@ -519,7 +518,7 @@ export const buildAttribute = (key, value) => {
|
|
|
519
518
|
};
|
|
520
519
|
|
|
521
520
|
export const buildExpression = (expr) => {
|
|
522
|
-
if (expr
|
|
521
|
+
if (isNull(expr)) return buildNull();
|
|
523
522
|
|
|
524
523
|
switch (typeof expr) {
|
|
525
524
|
case 'boolean':
|
|
@@ -572,7 +571,7 @@ export const buildNodeMatcher = (flags, language, type, attributes = {}) => {
|
|
|
572
571
|
{
|
|
573
572
|
openToken: t.s_node(l.CSTML, 'Punctuator', '<'),
|
|
574
573
|
language: buildLanguage(language_),
|
|
575
|
-
languageSeparator: language_ && type
|
|
574
|
+
languageSeparator: language_ && type ? t.s_node(l.CSTML, 'Punctuator', ':') : t.null_node(),
|
|
576
575
|
flags: flags_,
|
|
577
576
|
type: buildIdentifier(type),
|
|
578
577
|
attributes: attributes_,
|
package/lib/deembed.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const { isArray } = Array;
|
|
2
|
+
const isString = (val) => typeof val === 'string';
|
|
3
|
+
const isNumber = (val) => typeof val === 'number';
|
|
4
|
+
|
|
5
|
+
export const deembedExpression = (expr) => {
|
|
6
|
+
if (isString(expr) || expr == null || typeof expr === 'boolean' || isNumber(expr)) {
|
|
7
|
+
return expr;
|
|
8
|
+
} else if (isArray(expr)) {
|
|
9
|
+
return expr.map((value) => deembedExpression(value));
|
|
10
|
+
} else if (typeof expr === 'object') {
|
|
11
|
+
return Object.fromEntries(
|
|
12
|
+
Object.entries(expr.value).map(({ 0: key, 1: value }) => [key, deembedExpression(value)]),
|
|
13
|
+
);
|
|
14
|
+
} else {
|
|
15
|
+
throw new Error();
|
|
16
|
+
}
|
|
17
|
+
};
|
package/lib/embed.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { buildEmbeddedExpression } from './internal-builders.js';
|
|
2
|
+
|
|
3
|
+
const { isArray } = Array;
|
|
4
|
+
const isString = (val) => typeof val === 'string';
|
|
5
|
+
const isNumber = (val) => typeof val === 'number';
|
|
6
|
+
|
|
7
|
+
export const embedExpression = (expr) => {
|
|
8
|
+
if (isString(expr) || expr == null || typeof expr === 'boolean' || isNumber(expr)) {
|
|
9
|
+
return expr;
|
|
10
|
+
} else if (isArray(expr)) {
|
|
11
|
+
return expr.map((value) => embedExpression(value));
|
|
12
|
+
} else if (typeof expr === 'object') {
|
|
13
|
+
return buildEmbeddedExpression(
|
|
14
|
+
Object.fromEntries(
|
|
15
|
+
Object.entries(expr).map(({ 0: key, 1: value }) => [key, embedExpression(value)]),
|
|
16
|
+
),
|
|
17
|
+
);
|
|
18
|
+
} else {
|
|
19
|
+
throw new Error();
|
|
20
|
+
}
|
|
21
|
+
};
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { getCooked } from '@bablr/agast-helpers/tree';
|
|
1
|
+
import { getCooked, isNull } from '@bablr/agast-helpers/tree';
|
|
2
|
+
import * as sym from '@bablr/agast-helpers/symbols';
|
|
2
3
|
|
|
3
4
|
export * from './builders.js';
|
|
4
5
|
|
|
@@ -31,28 +32,24 @@ const reifyFlags = (flags) => {
|
|
|
31
32
|
let { triviaToken, escapeToken, tokenToken, expressionToken, intrinsicToken } = flags.properties;
|
|
32
33
|
|
|
33
34
|
return {
|
|
34
|
-
token:
|
|
35
|
-
escape:
|
|
36
|
-
trivia:
|
|
37
|
-
intrinsic:
|
|
38
|
-
expression:
|
|
35
|
+
token: reifyExpression(tokenToken),
|
|
36
|
+
escape: reifyExpression(escapeToken),
|
|
37
|
+
trivia: reifyExpression(triviaToken),
|
|
38
|
+
intrinsic: reifyExpression(intrinsicToken),
|
|
39
|
+
expression: reifyExpression(expressionToken),
|
|
39
40
|
};
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
export const reifyLanguage = (language) => {
|
|
43
44
|
const value = reifyExpression(language);
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
throw new Error('bad language');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return value;
|
|
46
|
+
return typeof value === 'string' && !value.startsWith('https://') ? [value] : value;
|
|
50
47
|
};
|
|
51
48
|
|
|
52
49
|
export const reifyExpression = (node) => {
|
|
53
50
|
if (node instanceof Promise) throw new Error();
|
|
54
51
|
|
|
55
|
-
if (!node) return null;
|
|
52
|
+
if (!node || node.type === sym.null) return null;
|
|
56
53
|
|
|
57
54
|
if (node.language === 'https://bablr.org/languages/core/en/cstml') {
|
|
58
55
|
switch (node.type) {
|
|
@@ -73,7 +70,7 @@ export const reifyExpression = (node) => {
|
|
|
73
70
|
|
|
74
71
|
name = reifyExpression(name);
|
|
75
72
|
|
|
76
|
-
return { type: 'Reference', value: { name, isArray:
|
|
73
|
+
return { type: 'Reference', value: { name, isArray: !isNull(arrayOperatorToken) } };
|
|
77
74
|
}
|
|
78
75
|
|
|
79
76
|
case 'Literal': {
|
|
@@ -87,17 +84,16 @@ export const reifyExpression = (node) => {
|
|
|
87
84
|
}
|
|
88
85
|
|
|
89
86
|
case 'OpenNodeTag': {
|
|
90
|
-
let { flags, language, type, attributes
|
|
87
|
+
let { flags, language, type, attributes } = node.properties;
|
|
91
88
|
|
|
92
89
|
flags = reifyFlags(flags);
|
|
93
90
|
language = reifyLanguage(language);
|
|
94
91
|
type = reifyExpression(type);
|
|
95
92
|
attributes = reifyAttributes(attributes);
|
|
96
|
-
intrinsicValue = reifyExpression(intrinsicValue);
|
|
97
93
|
|
|
98
94
|
return {
|
|
99
95
|
type: 'OpenNodeTag',
|
|
100
|
-
value: { flags, language, type,
|
|
96
|
+
value: { flags, language, type, attributes },
|
|
101
97
|
};
|
|
102
98
|
}
|
|
103
99
|
|
|
@@ -119,6 +115,10 @@ export const reifyExpression = (node) => {
|
|
|
119
115
|
return node.properties.sign === '-' ? -Infinity : Infinity;
|
|
120
116
|
}
|
|
121
117
|
|
|
118
|
+
case 'Punctuator': {
|
|
119
|
+
return getCooked(node);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
122
|
case 'String':
|
|
123
123
|
return node.properties.content ? getCooked(node.properties.content) : '';
|
|
124
124
|
|
|
@@ -148,7 +148,7 @@ export const reifyExpression = (node) => {
|
|
|
148
148
|
let { flags, language, type, attributes, intrinsicValue } = node.properties;
|
|
149
149
|
|
|
150
150
|
flags = reifyFlags(flags);
|
|
151
|
-
language =
|
|
151
|
+
language = reifyLanguage(language);
|
|
152
152
|
type = reifyExpression(type);
|
|
153
153
|
attributes = reifyAttributes(attributes);
|
|
154
154
|
intrinsicValue = reifyExpression(intrinsicValue);
|
|
@@ -205,7 +205,7 @@ export const reifyExpression = (node) => {
|
|
|
205
205
|
};
|
|
206
206
|
|
|
207
207
|
export const reifyExpressionShallow = (node) => {
|
|
208
|
-
if (!node) return null;
|
|
208
|
+
if (!node || node.type === sym.null) return null;
|
|
209
209
|
|
|
210
210
|
if (
|
|
211
211
|
![
|
|
@@ -244,7 +244,7 @@ export const reifyAttributes = (attributes) => {
|
|
|
244
244
|
if (attr.type === 'MappingAttribute') {
|
|
245
245
|
return [reifyExpression(attr.properties.key), reifyExpression(attr.properties.value)];
|
|
246
246
|
} else if (attr.type === 'BooleanAttribute') {
|
|
247
|
-
return [reifyExpression(attr.properties.key),
|
|
247
|
+
return [reifyExpression(attr.properties.key), isNull(attr.properties.negateToken)];
|
|
248
248
|
} else {
|
|
249
249
|
throw new Error();
|
|
250
250
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@bablr/agast-helpers/builders';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/agast-vm-helpers",
|
|
3
3
|
"description": "Helper functions for working with the BABLR VM",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"author": "Conrad Buck<conartist6@gmail.com>",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -9,13 +9,16 @@
|
|
|
9
9
|
],
|
|
10
10
|
"exports": {
|
|
11
11
|
".": "./lib/index.js",
|
|
12
|
-
"./facades": "./lib/facades.js",
|
|
13
12
|
"./builders": "./lib/builders.js",
|
|
13
|
+
"./deembed": "./lib/deembed.js",
|
|
14
|
+
"./embed": "./lib/embed.js",
|
|
15
|
+
"./facades": "./lib/facades.js",
|
|
16
|
+
"./internal-builders": "./lib/internal-builders.js",
|
|
14
17
|
"./languages": "./lib/languages.js"
|
|
15
18
|
},
|
|
16
19
|
"sideEffects": false,
|
|
17
20
|
"dependencies": {
|
|
18
|
-
"@bablr/agast-helpers": "0.
|
|
21
|
+
"@bablr/agast-helpers": "0.3.0"
|
|
19
22
|
},
|
|
20
23
|
"devDependencies": {
|
|
21
24
|
"@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#49f5952efed27f94ee9b94340eb1563c440bf64e",
|