@bablr/boot 0.9.0 → 0.10.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/index.js +3 -2
- package/lib/languages/cstml.js +58 -40
- package/lib/languages/json.js +12 -2
- package/lib/languages/spamex.js +13 -9
- package/lib/match.js +1 -3
- package/lib/miniparser.js +12 -12
- package/lib/path.js +1 -36
- package/package.json +4 -4
package/lib/index.js
CHANGED
|
@@ -50,8 +50,9 @@ export const buildTag = (language, defaultType) => {
|
|
|
50
50
|
});
|
|
51
51
|
};
|
|
52
52
|
|
|
53
|
-
export const parse = (language, type, sourceText) => {
|
|
54
|
-
|
|
53
|
+
export const parse = (language, type, sourceText, expressions = []) => {
|
|
54
|
+
let source = Array.isArray(sourceText) ? sourceText : [sourceText];
|
|
55
|
+
return new TemplateParser(language, source, expressions).eval({
|
|
55
56
|
language: language.name,
|
|
56
57
|
type,
|
|
57
58
|
});
|
package/lib/languages/cstml.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as sym from '@bablr/agast-vm-helpers/symbols';
|
|
2
2
|
import * as JSON from './json.js';
|
|
3
|
-
import {
|
|
3
|
+
import { get, sourceTextFor } from '@bablr/agast-helpers/tree';
|
|
4
4
|
|
|
5
5
|
const _ = /\s+/y;
|
|
6
6
|
const PN = 'Punctuator';
|
|
@@ -50,7 +50,7 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
50
50
|
Document(p) {
|
|
51
51
|
p.eatProduction('DoctypeTag', { path: 'doctype' });
|
|
52
52
|
p.eatMatchTrivia(_);
|
|
53
|
-
p.eatProduction('Node', { path: 'tree' }, {
|
|
53
|
+
p.eatProduction('Node', { path: 'tree' }, { forceFragment: true });
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
// @Node
|
|
@@ -98,25 +98,19 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
98
98
|
|
|
99
99
|
// @Node
|
|
100
100
|
Node(p, props) {
|
|
101
|
-
let open = p.eatProduction('OpenNodeTag', { path: 'open' }, props);
|
|
101
|
+
let open = p.eatProduction('OpenNodeTag', { path: 'open', noInterpolate: true }, props);
|
|
102
102
|
|
|
103
103
|
p.eatMatchTrivia(_);
|
|
104
104
|
|
|
105
|
-
if (open.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
while (!(p.match('</') || p.done)) {
|
|
111
|
-
p.eatProduction('NodeChild', { path: 'children[]' });
|
|
105
|
+
if (open.attributes.balanced) {
|
|
106
|
+
let token = !!get(['flags', 'token'], open);
|
|
107
|
+
|
|
108
|
+
while (p.atExpression || !(p.match(/<\/[^/]/y) || p.done)) {
|
|
109
|
+
p.eatProduction('NodeChild', { path: 'children[]' }, { token });
|
|
112
110
|
p.eatMatchTrivia(_);
|
|
113
|
-
if (p.idx === lastIndex) break;
|
|
114
|
-
lastIndex = p.idx;
|
|
115
111
|
}
|
|
116
|
-
}
|
|
117
112
|
|
|
118
|
-
|
|
119
|
-
p.eatProduction('CloseNodeTag', { path: 'close' });
|
|
113
|
+
p.eatProduction('CloseNodeTag', { path: 'close', noInterpolate: true });
|
|
120
114
|
}
|
|
121
115
|
}
|
|
122
116
|
|
|
@@ -129,15 +123,17 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
129
123
|
|
|
130
124
|
if (token) {
|
|
131
125
|
if (p.match(/<\*?@/y)) {
|
|
132
|
-
p.eatProduction('
|
|
126
|
+
p.eatProduction('Property');
|
|
133
127
|
} else {
|
|
134
128
|
p.eatProduction('LiteralTag');
|
|
135
129
|
}
|
|
136
130
|
} else {
|
|
137
|
-
if (p.match(/[:<a-zA-Z`\\\u{80}-\u{10ffff}.]|[.#@]/uy)) {
|
|
131
|
+
if (p.match(/[:<a-zA-Z`\\\u{80}-\u{10ffff}.]|[.#@_]/uy) || p.atExpression) {
|
|
138
132
|
p.eatProduction('Property');
|
|
139
133
|
} else if (p.match(/['"]/y)) {
|
|
140
|
-
p.eatProduction('
|
|
134
|
+
p.eatProduction('Property');
|
|
135
|
+
} else {
|
|
136
|
+
p.fail();
|
|
141
137
|
}
|
|
142
138
|
}
|
|
143
139
|
}
|
|
@@ -157,18 +153,23 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
157
153
|
|
|
158
154
|
// @Node
|
|
159
155
|
Property(p) {
|
|
160
|
-
|
|
161
|
-
|
|
156
|
+
let ref = null;
|
|
157
|
+
if (p.match(/[a-zA-Z`\\\u{80}-\u{10ffff}.]|[.#@_]/uy)) {
|
|
158
|
+
ref = p.eatProduction('ReferenceTag', { path: 'reference' });
|
|
162
159
|
}
|
|
163
160
|
p.eatMatchTrivia(_);
|
|
164
161
|
if (p.match(':')) {
|
|
165
162
|
p.eatProduction('BindingTag', { path: 'binding' });
|
|
166
163
|
p.eatMatchTrivia(_);
|
|
167
164
|
}
|
|
168
|
-
|
|
165
|
+
let refType = ref && get('type', ref);
|
|
166
|
+
p.eatProduction('PropertyValue', {
|
|
167
|
+
path: 'value',
|
|
168
|
+
allowFragment: refType && sourceTextFor(refType) === '_',
|
|
169
|
+
});
|
|
169
170
|
}
|
|
170
171
|
|
|
171
|
-
PropertyValue(p) {
|
|
172
|
+
PropertyValue(p, { allowFragment }) {
|
|
172
173
|
if (p.match('null')) {
|
|
173
174
|
p.eatProduction('NullTag');
|
|
174
175
|
} else if (p.match(/\[\]|undefined/y)) {
|
|
@@ -176,7 +177,7 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
176
177
|
} else if (p.match('<//>')) {
|
|
177
178
|
p.eatProduction('GapTag');
|
|
178
179
|
} else {
|
|
179
|
-
p.eatProduction('Node');
|
|
180
|
+
p.eatProduction('Node', { allowFragment, propertyValue: true });
|
|
180
181
|
}
|
|
181
182
|
}
|
|
182
183
|
|
|
@@ -185,11 +186,16 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
185
186
|
p.eatMatch('*', PN, { path: 'tokenToken' });
|
|
186
187
|
p.eatMatch('$', PN, { path: 'hasGapToken' });
|
|
187
188
|
p.eatMatch('_', PN, { path: 'fragmentToken' });
|
|
188
|
-
p.eatMatch('_', PN, { path: '
|
|
189
|
+
p.eatMatch('_', PN, { path: 'multiFragmentToken' });
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
// @Node
|
|
192
|
-
OpenNodeTag(p, {
|
|
193
|
+
OpenNodeTag(p, { forceFragment = false, allowFragment = true, propertyValue = false } = {}) {
|
|
194
|
+
if (p.match(/['"]/y)) {
|
|
195
|
+
p.eatProduction('JSON:String', { path: 'literalValue' });
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
193
199
|
p.eat('<', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
|
|
194
200
|
|
|
195
201
|
let flags = null;
|
|
@@ -199,13 +205,23 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
199
205
|
|
|
200
206
|
let sp = null;
|
|
201
207
|
|
|
202
|
-
|
|
208
|
+
let fragmentFlag = get('fragmentToken', flags);
|
|
209
|
+
let multiFragmentFlag = get('multiFragmentFlag', flags);
|
|
210
|
+
let tokenFlag = get('tokenToken', flags);
|
|
211
|
+
|
|
212
|
+
if (propertyValue && fragmentFlag && !multiFragmentFlag) throw new Error();
|
|
203
213
|
|
|
204
|
-
if (
|
|
214
|
+
if (forceFragment && !fragmentFlag) throw new Error();
|
|
215
|
+
|
|
216
|
+
if (!fragmentFlag && !p.match(/./sy)) {
|
|
217
|
+
throw new Error();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (fragmentFlag && !allowFragment) {
|
|
205
221
|
throw new Error();
|
|
206
222
|
}
|
|
207
223
|
|
|
208
|
-
if (!
|
|
224
|
+
if (!fragmentFlag) {
|
|
209
225
|
p.eatProduction('Identifier', { path: 'type' });
|
|
210
226
|
|
|
211
227
|
sp = p.eatMatchTrivia(_);
|
|
@@ -213,24 +229,24 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
213
229
|
let iv;
|
|
214
230
|
|
|
215
231
|
if (sp && (p.match(/['"]/y) || p.atExpression)) {
|
|
216
|
-
iv = p.eatProduction('JSON:String', { path: '
|
|
232
|
+
iv = p.eatProduction('JSON:String', { path: 'literalValue' });
|
|
217
233
|
|
|
218
234
|
sp = p.eatMatchTrivia(_);
|
|
219
235
|
}
|
|
220
236
|
|
|
221
|
-
if (!flags.properties.tokenToken && iv) {
|
|
222
|
-
throw new Error();
|
|
223
|
-
}
|
|
224
|
-
|
|
225
237
|
if (p.match('{') || p.atExpression) {
|
|
226
|
-
p.eatProduction('JSON:Object');
|
|
238
|
+
p.eatProduction('JSON:Object', { path: 'attributes' });
|
|
227
239
|
sp = p.eatMatchTrivia(_);
|
|
228
240
|
}
|
|
229
241
|
|
|
230
242
|
p.eatMatchTrivia(_);
|
|
231
243
|
}
|
|
232
|
-
p.eatMatch('/', PN, { path: '
|
|
244
|
+
let sc = p.eatMatch('/', PN, { path: 'selfClosingToken' });
|
|
233
245
|
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
246
|
+
|
|
247
|
+
const balanced = !sc && (p.path.depth > 0 || p.span.type !== 'Bare');
|
|
248
|
+
|
|
249
|
+
return { attrs: { balanced } };
|
|
234
250
|
}
|
|
235
251
|
|
|
236
252
|
// @Node
|
|
@@ -274,7 +290,7 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
274
290
|
let lit, esc;
|
|
275
291
|
do {
|
|
276
292
|
if ((esc = p.match('\\'))) {
|
|
277
|
-
p.
|
|
293
|
+
p.eatEscape(/\\(u(\{[0-9a-fA-F]\}|\d{4}))/y);
|
|
278
294
|
} else {
|
|
279
295
|
if (!quoted) {
|
|
280
296
|
lit = p.eatMatchLiteral(/[a-zA-Z\u{80}-\u{10ffff}][a-zA-Z0-9_\u{80}-\u{10ffff}-]*/uy);
|
|
@@ -296,10 +312,12 @@ export const grammar = class CSTMLMiniparserGrammar {
|
|
|
296
312
|
|
|
297
313
|
// @Node
|
|
298
314
|
ReferenceTag(p) {
|
|
299
|
-
let
|
|
300
|
-
if ((
|
|
301
|
-
p.eat(
|
|
302
|
-
}
|
|
315
|
+
let type;
|
|
316
|
+
if ((type = p.match(/[.#@_]/y))) {
|
|
317
|
+
p.eat(type, PN, { path: 'type' });
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (!type || type === '#') {
|
|
303
321
|
p.eatProduction('Identifier', { path: 'name' });
|
|
304
322
|
}
|
|
305
323
|
p.eatMatchTrivia(_);
|
package/lib/languages/json.js
CHANGED
|
@@ -7,7 +7,7 @@ import * as Regex from './regex.js';
|
|
|
7
7
|
const _ = /\s+/y;
|
|
8
8
|
const PN = 'Punctuator';
|
|
9
9
|
const KW = 'Keyword';
|
|
10
|
-
const
|
|
10
|
+
const LIT = 'Identifier';
|
|
11
11
|
|
|
12
12
|
export const name = 'JSON';
|
|
13
13
|
|
|
@@ -34,6 +34,7 @@ export const covers = new Map([
|
|
|
34
34
|
'Integer',
|
|
35
35
|
'String',
|
|
36
36
|
'StringContent',
|
|
37
|
+
'Identifier',
|
|
37
38
|
]),
|
|
38
39
|
],
|
|
39
40
|
['Expression', new Set(['Object', 'Array', 'Boolean', 'Null', 'Number', 'String'])],
|
|
@@ -125,7 +126,11 @@ export const grammar = class JSONMiniparserGrammar {
|
|
|
125
126
|
|
|
126
127
|
// @Node
|
|
127
128
|
Property(p) {
|
|
128
|
-
p.
|
|
129
|
+
if (p.match(/['"]/y)) {
|
|
130
|
+
p.eatProduction('String', { path: 'key' });
|
|
131
|
+
} else {
|
|
132
|
+
p.eatProduction('Identifier', { path: 'key' });
|
|
133
|
+
}
|
|
129
134
|
p.eatMatchTrivia(_);
|
|
130
135
|
p.eat(':', PN, { path: 'mapToken' });
|
|
131
136
|
p.eatMatchTrivia(_);
|
|
@@ -216,6 +221,11 @@ export const grammar = class JSONMiniparserGrammar {
|
|
|
216
221
|
p.eatLiteral(/\d/y);
|
|
217
222
|
}
|
|
218
223
|
|
|
224
|
+
// @Node
|
|
225
|
+
Identifier(p) {
|
|
226
|
+
p.eat(/[a-zA-Z]+/y, LIT, { path: 'content' });
|
|
227
|
+
}
|
|
228
|
+
|
|
219
229
|
// @Node
|
|
220
230
|
String(p) {
|
|
221
231
|
const q = p.match(/['"]/y) || '"';
|
package/lib/languages/spamex.js
CHANGED
|
@@ -2,6 +2,7 @@ import * as sym from '@bablr/agast-vm-helpers/symbols';
|
|
|
2
2
|
import * as Regex from './regex.js';
|
|
3
3
|
import * as CSTML from './cstml.js';
|
|
4
4
|
import * as JSON from './json.js';
|
|
5
|
+
import { get } from '@bablr/agast-helpers/path';
|
|
5
6
|
|
|
6
7
|
const _ = /\s+/y;
|
|
7
8
|
const PN = 'Punctuator';
|
|
@@ -92,15 +93,18 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
92
93
|
|
|
93
94
|
// @Node
|
|
94
95
|
ReferenceMatcher(p) {
|
|
95
|
-
let name;
|
|
96
|
-
if ((
|
|
97
|
-
|
|
98
|
-
}
|
|
96
|
+
let name, type;
|
|
97
|
+
if ((type = p.match(/[.#@]/y))) {
|
|
98
|
+
p.eat(type, PN, { path: 'type' });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if ((!type || type === '#') && p.match(/[A-Za-z]/y)) {
|
|
99
102
|
name = p.eatProduction('CSTML:Identifier', { path: 'name' });
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
let open =
|
|
103
|
-
name
|
|
106
|
+
(name || type) &&
|
|
107
|
+
p.eatMatch('[', PN, { path: 'openIndexToken', startSpan: 'Index', balanced: ']' });
|
|
104
108
|
|
|
105
109
|
if (open) {
|
|
106
110
|
p.eatMatchTrivia(_);
|
|
@@ -143,10 +147,10 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
143
147
|
BasicNodeMatcher(p) {
|
|
144
148
|
let open = p.eatProduction('OpenNodeMatcher', { path: 'open' });
|
|
145
149
|
|
|
146
|
-
if (!open
|
|
150
|
+
if (!get('selfClosingToken', open)) {
|
|
147
151
|
p.eatMatchTrivia(_);
|
|
148
152
|
|
|
149
|
-
if (open
|
|
153
|
+
if (get('flags', open)?.token) {
|
|
150
154
|
// p.eatProduction('NodeChild', { path: 'children[]' }, { token: true });
|
|
151
155
|
// p.eatMatchTrivia(_);
|
|
152
156
|
} else {
|
|
@@ -179,7 +183,7 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
179
183
|
let sp = p.eatMatchTrivia(_);
|
|
180
184
|
|
|
181
185
|
if (sp && ((p.match(/['"/]/y) && !p.match('/>')) || p.atExpression)) {
|
|
182
|
-
p.eatProduction('StringMatcher', { path: '
|
|
186
|
+
p.eatProduction('StringMatcher', { path: 'literalValue' });
|
|
183
187
|
|
|
184
188
|
sp = p.eatMatchTrivia(_);
|
|
185
189
|
}
|
|
@@ -190,7 +194,7 @@ export const grammar = class SpamexMiniparserGrammar {
|
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
p.eatMatchTrivia(_);
|
|
193
|
-
p.eatMatch('/', PN, { path: '
|
|
197
|
+
p.eatMatch('/', PN, { path: 'selfClosingToken' });
|
|
194
198
|
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
195
199
|
}
|
|
196
200
|
|
package/lib/match.js
CHANGED
|
@@ -51,8 +51,7 @@ export class Match {
|
|
|
51
51
|
|
|
52
52
|
if (isNode && !isCover) {
|
|
53
53
|
path.node = createNode();
|
|
54
|
-
path.node.type = type;
|
|
55
|
-
path.node.language = resolvedLanguage.canonicalURL;
|
|
54
|
+
path.node.type = Symbol.for(type);
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
return new Match(null, resolvedLanguage, id, attrs, path);
|
|
@@ -78,7 +77,6 @@ export class Match {
|
|
|
78
77
|
}
|
|
79
78
|
path.node = createNode();
|
|
80
79
|
path.node.type = Symbol.for(type);
|
|
81
|
-
path.node.language = resolvedLanguage.canonicalURL;
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
return new Match(this, resolvedLanguage, id, { ...baseAttrs, ...attrs }, path);
|
package/lib/miniparser.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
nodeFlags,
|
|
17
17
|
} from '@bablr/agast-helpers/builders';
|
|
18
18
|
import { add, buildToken, shift } from '@bablr/agast-helpers/tree';
|
|
19
|
-
import * as
|
|
19
|
+
import * as Tags from '@bablr/agast-helpers/tags';
|
|
20
20
|
import { buildPathSegment, get } from '@bablr/agast-helpers/path';
|
|
21
21
|
import { parseReference } from '@bablr/agast-helpers/shorthand';
|
|
22
22
|
|
|
@@ -180,12 +180,12 @@ export class TemplateParser {
|
|
|
180
180
|
|
|
181
181
|
if (isArray(result)) {
|
|
182
182
|
for (const value of result) {
|
|
183
|
-
node.
|
|
183
|
+
node.tags = Tags.push(node.tags, path);
|
|
184
184
|
|
|
185
185
|
add(node, path, value);
|
|
186
186
|
}
|
|
187
187
|
} else {
|
|
188
|
-
node.
|
|
188
|
+
node.tags = Tags.push(node.tags, path);
|
|
189
189
|
|
|
190
190
|
add(node, path, result);
|
|
191
191
|
}
|
|
@@ -201,7 +201,7 @@ export class TemplateParser {
|
|
|
201
201
|
|
|
202
202
|
if (isNode) {
|
|
203
203
|
let { node } = this.path;
|
|
204
|
-
node.
|
|
204
|
+
node.tags = Tags.push(node.tags, buildOpenNodeTag(nodeFlags, node.type));
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
const result = getPrototypeOf(grammar)[type].call(grammar, this, props);
|
|
@@ -214,14 +214,14 @@ export class TemplateParser {
|
|
|
214
214
|
const { node } = this.path;
|
|
215
215
|
if (result?.attrs) {
|
|
216
216
|
node.attributes = result.attrs;
|
|
217
|
-
node.
|
|
217
|
+
node.tags = Tags.replaceAt(
|
|
218
218
|
0,
|
|
219
|
-
node.
|
|
219
|
+
node.tags,
|
|
220
220
|
buildOpenNodeTag(nodeFlags, node.type, result.attrs),
|
|
221
221
|
);
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
node.
|
|
224
|
+
node.tags = Tags.push(node.tags, buildCloseNodeTag());
|
|
225
225
|
|
|
226
226
|
if (parentPath?.node && !covers.has(type)) {
|
|
227
227
|
const path = parseReference(this.m.attrs.path);
|
|
@@ -244,9 +244,9 @@ export class TemplateParser {
|
|
|
244
244
|
if (this.path?.node) {
|
|
245
245
|
const isTag = (child) => [LiteralTag, Escape].includes(child.type);
|
|
246
246
|
|
|
247
|
-
const {
|
|
247
|
+
const { tags } = this.path.node;
|
|
248
248
|
|
|
249
|
-
if (find(isTag,
|
|
249
|
+
if (find(isTag, Tags.traverse(tags)) && every(isTag, Tags.traverse(tags))) {
|
|
250
250
|
throw new Error('strings must be wrapped in nodes');
|
|
251
251
|
}
|
|
252
252
|
}
|
|
@@ -306,7 +306,7 @@ export class TemplateParser {
|
|
|
306
306
|
|
|
307
307
|
// get the most recently produced node and detach it from its parent
|
|
308
308
|
|
|
309
|
-
const ref =
|
|
309
|
+
const ref = Tags.getAt(-1, node.tags).value.tags[0];
|
|
310
310
|
|
|
311
311
|
if (!ref.value.flags.expression) throw new Error();
|
|
312
312
|
|
|
@@ -432,7 +432,7 @@ export class TemplateParser {
|
|
|
432
432
|
|
|
433
433
|
this.idx += result.length;
|
|
434
434
|
|
|
435
|
-
this.node.
|
|
435
|
+
this.node.tags = Tags.push(this.node.tags, buildLiteralTag(result));
|
|
436
436
|
|
|
437
437
|
return result;
|
|
438
438
|
}
|
|
@@ -443,7 +443,7 @@ export class TemplateParser {
|
|
|
443
443
|
if (result) {
|
|
444
444
|
this.idx += result.length;
|
|
445
445
|
|
|
446
|
-
this.node.
|
|
446
|
+
this.node.tags = Tags.push(this.node.tags, buildLiteralTag(result));
|
|
447
447
|
}
|
|
448
448
|
|
|
449
449
|
return result;
|
package/lib/path.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
const { hasOwn } = Object;
|
|
2
|
-
const { isArray } = Array;
|
|
3
|
-
|
|
4
1
|
export class Path {
|
|
5
2
|
constructor(id, attributes, parent = null) {
|
|
6
3
|
this.id = id;
|
|
7
4
|
this.attributes = attributes;
|
|
8
5
|
this.parent = parent;
|
|
6
|
+
this.depth = parent ? parent.depth + 1 : 0
|
|
9
7
|
|
|
10
8
|
this.node = null;
|
|
11
9
|
}
|
|
@@ -34,36 +32,3 @@ export class Path {
|
|
|
34
32
|
return new Path(id, attrs);
|
|
35
33
|
}
|
|
36
34
|
}
|
|
37
|
-
|
|
38
|
-
export class PathResolver {
|
|
39
|
-
constructor(node) {
|
|
40
|
-
this.node = node;
|
|
41
|
-
this.counters = {};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
get(path) {
|
|
45
|
-
const { node, counters } = this;
|
|
46
|
-
|
|
47
|
-
const { isArray: pathIsArray, name } = path;
|
|
48
|
-
|
|
49
|
-
if (!hasOwn(node.properties, name)) {
|
|
50
|
-
throw new Error(`cannot resolve {path: ${name}}`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
let value = node.properties[name];
|
|
54
|
-
|
|
55
|
-
if (pathIsArray) {
|
|
56
|
-
if (!isArray(value)) {
|
|
57
|
-
throw new Error(`cannot resolve {path: ${name}}: not an array`);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const counter = counters[name] ?? 0;
|
|
61
|
-
|
|
62
|
-
counters[name] = counter + 1;
|
|
63
|
-
|
|
64
|
-
value = value[counter];
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return value;
|
|
68
|
-
}
|
|
69
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/boot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Compile-time tools for bootstrapping BABLR VM",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=12.0.0"
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
],
|
|
21
21
|
"sideEffects": false,
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@bablr/agast-helpers": "0.
|
|
24
|
-
"@bablr/agast-vm-helpers": "0.
|
|
25
|
-
"@iter-tools/imm-stack": "1.
|
|
23
|
+
"@bablr/agast-helpers": "0.9.0",
|
|
24
|
+
"@bablr/agast-vm-helpers": "0.9.0",
|
|
25
|
+
"@iter-tools/imm-stack": "1.2.0",
|
|
26
26
|
"escape-string-regexp": "5.0.0",
|
|
27
27
|
"iter-tools-es": "^7.0.2"
|
|
28
28
|
},
|