@bablr/boot 0.6.0 → 0.6.2
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 +1 -1
- package/lib/languages/cstml.js +138 -7
- package/lib/languages/instruction.js +19 -4
- package/lib/languages/spamex.js +12 -10
- package/lib/miniparser.js +14 -4
- package/lib/utils.js +1 -1
- package/package.json +13 -9
package/lib/index.js
CHANGED
|
@@ -220,7 +220,7 @@ const getAgASTValue = (language, miniNode) => {
|
|
|
220
220
|
const str = buildTag(cstml, 'String');
|
|
221
221
|
const num = buildTag(cstml, 'Integer');
|
|
222
222
|
const cst = buildTag(cstml, 'Node');
|
|
223
|
-
const spam = buildTag(spamex, '
|
|
223
|
+
const spam = buildTag(spamex, 'Matcher');
|
|
224
224
|
const re = buildTag(regex, 'Pattern');
|
|
225
225
|
const i = buildTag(instruction, 'Call');
|
|
226
226
|
|
package/lib/languages/cstml.js
CHANGED
|
@@ -7,6 +7,7 @@ const _ = /\s+/y;
|
|
|
7
7
|
const PN = 'Punctuator';
|
|
8
8
|
const ID = 'Identifier';
|
|
9
9
|
const KW = 'Keyword';
|
|
10
|
+
const LIT = 'Literal';
|
|
10
11
|
|
|
11
12
|
const name = 'CSTML';
|
|
12
13
|
|
|
@@ -66,9 +67,12 @@ const covers = buildCovers({
|
|
|
66
67
|
'NullTag',
|
|
67
68
|
'GapTag',
|
|
68
69
|
'Node',
|
|
70
|
+
'Fragment',
|
|
69
71
|
'IdentifierPath',
|
|
70
72
|
'OpenNodeTag',
|
|
71
73
|
'CloseNodeTag',
|
|
74
|
+
'OpenFragmentTag',
|
|
75
|
+
'CloseFragmentTag',
|
|
72
76
|
'Tag',
|
|
73
77
|
'Number',
|
|
74
78
|
'Digit',
|
|
@@ -76,10 +80,26 @@ const covers = buildCovers({
|
|
|
76
80
|
'Content',
|
|
77
81
|
'UnsignedInteger',
|
|
78
82
|
'Flags',
|
|
83
|
+
'Array',
|
|
84
|
+
'Object',
|
|
85
|
+
'Boolean',
|
|
86
|
+
'Null',
|
|
87
|
+
'Identifier',
|
|
88
|
+
'JSONProperty',
|
|
89
|
+
'JSONExpression',
|
|
79
90
|
],
|
|
80
91
|
[sym.fragment]: ['Attributes'],
|
|
81
92
|
Attribute: ['MappingAttribute', 'BooleanAttribute'],
|
|
82
|
-
|
|
93
|
+
JSONExpression: [
|
|
94
|
+
'Boolean',
|
|
95
|
+
'Null',
|
|
96
|
+
'Number',
|
|
97
|
+
'String',
|
|
98
|
+
'Array',
|
|
99
|
+
'Object',
|
|
100
|
+
'Identifier',
|
|
101
|
+
'Separator',
|
|
102
|
+
],
|
|
83
103
|
TagType: ['Identifier', 'GlobalIdentifier'],
|
|
84
104
|
Tag: ['LiteralTag', 'Trivia'],
|
|
85
105
|
PropertyValue: ['GapTag', 'Node', 'NullTag'],
|
|
@@ -92,7 +112,7 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
92
112
|
Document(p) {
|
|
93
113
|
p.eatProduction('DoctypeTag', { path: 'doctype' });
|
|
94
114
|
p.eatMatchTrivia(_);
|
|
95
|
-
p.eatProduction('
|
|
115
|
+
p.eatProduction('Fragment', { path: 'tree' });
|
|
96
116
|
}
|
|
97
117
|
|
|
98
118
|
// @Node
|
|
@@ -163,6 +183,25 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
163
183
|
}
|
|
164
184
|
}
|
|
165
185
|
|
|
186
|
+
// @Node
|
|
187
|
+
Fragment(p) {
|
|
188
|
+
let open = p.eatProduction('OpenFragmentTag', { path: 'open' });
|
|
189
|
+
|
|
190
|
+
p.eatMatchTrivia(_);
|
|
191
|
+
|
|
192
|
+
if (open.properties.flags?.token) {
|
|
193
|
+
p.eatProduction('NodeChild', { path: 'children[]' }, { token: true });
|
|
194
|
+
p.eatMatchTrivia(_);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
while (!(p.match('</') || p.done)) {
|
|
198
|
+
p.eatProduction('NodeChild', { path: 'children[]' });
|
|
199
|
+
p.eatMatchTrivia(_);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
p.eatProduction('CloseFragmentTag', { path: 'close' });
|
|
203
|
+
}
|
|
204
|
+
|
|
166
205
|
// @Node
|
|
167
206
|
Property(p) {
|
|
168
207
|
p.eatProduction('ReferenceTag', { path: 'reference' });
|
|
@@ -237,6 +276,27 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
237
276
|
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
238
277
|
}
|
|
239
278
|
|
|
279
|
+
// @Node
|
|
280
|
+
OpenFragmentTag(p) {
|
|
281
|
+
p.eat('<', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
|
|
282
|
+
|
|
283
|
+
let flags = null;
|
|
284
|
+
if (!p.atExpression) {
|
|
285
|
+
flags = p.eatProduction('Flags', { path: 'flags' });
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (p.done) {
|
|
289
|
+
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// @Node
|
|
295
|
+
CloseFragmentTag(p) {
|
|
296
|
+
p.eat('</', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
|
|
297
|
+
p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
|
|
298
|
+
}
|
|
299
|
+
|
|
240
300
|
// @Fragment
|
|
241
301
|
Attributes(p) {
|
|
242
302
|
let sp = true;
|
|
@@ -275,20 +335,28 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
275
335
|
p.eatMatchTrivia(_);
|
|
276
336
|
p.eat('=', PN, { path: 'mapToken' });
|
|
277
337
|
p.eatMatchTrivia(_);
|
|
278
|
-
p.eatProduction('
|
|
338
|
+
p.eatProduction('JSONExpression', { path: 'value' });
|
|
279
339
|
}
|
|
280
340
|
|
|
281
341
|
// @Cover
|
|
282
|
-
|
|
342
|
+
JSONExpression(p) {
|
|
283
343
|
if (p.match(/['"]/y)) {
|
|
284
344
|
p.eatProduction('String');
|
|
285
345
|
} else if (p.match(/[\d+-]/y)) {
|
|
286
346
|
p.eatProduction('Number');
|
|
347
|
+
} else if (p.match('[')) {
|
|
348
|
+
p.eatProduction('Array');
|
|
349
|
+
} else if (p.match('{')) {
|
|
350
|
+
p.eatProduction('Object');
|
|
351
|
+
} else if (p.match(/true|false/y)) {
|
|
352
|
+
p.eatProduction('Boolean');
|
|
353
|
+
} else if (p.match('null')) {
|
|
354
|
+
p.eatProduction('Null');
|
|
287
355
|
}
|
|
288
356
|
}
|
|
289
357
|
|
|
290
358
|
TagType(p) {
|
|
291
|
-
if (p.match(/[a-zA-Z\.]+:/y)) {
|
|
359
|
+
if (p.match(/['"]|[a-zA-Z\.]+:/y)) {
|
|
292
360
|
p.eatProduction('LanguageReference', { path: 'language' });
|
|
293
361
|
p.eat(':', PN, { path: 'namespaceSeparatorToken' });
|
|
294
362
|
p.eatProduction('Identifier', { path: 'type' });
|
|
@@ -352,10 +420,73 @@ const grammar = class CSTMLMiniparserGrammar {
|
|
|
352
420
|
}
|
|
353
421
|
|
|
354
422
|
// @Node
|
|
355
|
-
|
|
356
|
-
p.
|
|
423
|
+
Array(p) {
|
|
424
|
+
p.eat('[', PN, { path: 'openToken', balanced: ']' });
|
|
425
|
+
|
|
426
|
+
p.eatMatchTrivia(_);
|
|
427
|
+
|
|
428
|
+
let first = true;
|
|
429
|
+
let sep;
|
|
430
|
+
while (first || (sep && (p.match(/./y) || p.atExpression))) {
|
|
431
|
+
p.eatProduction('JSONExpression', { path: 'elements[]' });
|
|
432
|
+
if (p.match(/\s*,?/y)) {
|
|
433
|
+
sep = p.eatProduction('Separator', { path: 'separators[]' });
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
first = false;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
p.eat(']', PN, { path: 'closeToken', balancer: true });
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// @Node
|
|
443
|
+
Object(p) {
|
|
444
|
+
p.eat('{', PN, { path: 'openToken', balanced: '}' });
|
|
445
|
+
|
|
446
|
+
p.eatMatchTrivia(_);
|
|
447
|
+
|
|
448
|
+
let first = true;
|
|
449
|
+
let sep;
|
|
450
|
+
while (first || (sep && (p.match(/./y) || p.atExpression))) {
|
|
451
|
+
p.eatProduction('JSONProperty', { path: 'properties[]' });
|
|
452
|
+
if (p.match(/\s*,?/y)) {
|
|
453
|
+
sep = p.eatProduction('Separator', { path: 'separators[]' });
|
|
454
|
+
}
|
|
455
|
+
first = false;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
p.eatMatchTrivia(_);
|
|
459
|
+
|
|
460
|
+
p.eat('}', PN, { path: 'closeToken', balancer: true });
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// @Node
|
|
464
|
+
JSONProperty(p) {
|
|
465
|
+
p.eat(/[a-zA-Z]+/y, LIT, { path: 'key' });
|
|
466
|
+
p.eatMatchTrivia(_);
|
|
467
|
+
p.eat(':', PN, { path: 'mapToken' });
|
|
468
|
+
p.eatMatchTrivia(_);
|
|
469
|
+
p.eatProduction('JSONExpression', { path: 'value' });
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// @Node
|
|
473
|
+
Boolean(p) {
|
|
474
|
+
p.eat(/true|false/y, KW, { path: 'sigilToken' });
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// @Node
|
|
478
|
+
Null(p) {
|
|
479
|
+
p.eat('null', KW, { path: 'sigilToken' });
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
//@Node
|
|
483
|
+
Separator(p) {
|
|
484
|
+
p.eatMatchTrivia(_);
|
|
485
|
+
p.eatMatch(/,/y, PN, { path: 'separators[]' });
|
|
486
|
+
p.eatMatchTrivia(_);
|
|
357
487
|
}
|
|
358
488
|
|
|
489
|
+
//@Node
|
|
359
490
|
Number(p) {
|
|
360
491
|
if (p.match(/-?\d/y)) {
|
|
361
492
|
p.eatProduction('Integer');
|
|
@@ -29,6 +29,7 @@ const covers = buildCovers({
|
|
|
29
29
|
'Boolean',
|
|
30
30
|
'Null',
|
|
31
31
|
'Spamex:Matcher',
|
|
32
|
+
'Separator',
|
|
32
33
|
],
|
|
33
34
|
});
|
|
34
35
|
|
|
@@ -75,7 +76,9 @@ const grammar = class InstructionMiniparserGrammar {
|
|
|
75
76
|
let sep;
|
|
76
77
|
while (first || (sep && (p.match(/./y) || p.atExpression))) {
|
|
77
78
|
p.eatProduction('Property', { path: 'properties[]' });
|
|
78
|
-
|
|
79
|
+
if (p.match(/\s*,?/y)) {
|
|
80
|
+
sep = p.eatProduction('Separator', { path: 'separators[]' });
|
|
81
|
+
}
|
|
79
82
|
first = false;
|
|
80
83
|
}
|
|
81
84
|
|
|
@@ -103,7 +106,10 @@ const grammar = class InstructionMiniparserGrammar {
|
|
|
103
106
|
let sep;
|
|
104
107
|
while (first || (sep && (p.match(/./y) || p.atExpression))) {
|
|
105
108
|
p.eatProduction('Expression', { path: 'elements[]' });
|
|
106
|
-
|
|
109
|
+
if (p.match(/\s*,?/y)) {
|
|
110
|
+
sep = p.eatProduction('Separator', { path: 'separators[]' });
|
|
111
|
+
}
|
|
112
|
+
|
|
107
113
|
first = false;
|
|
108
114
|
}
|
|
109
115
|
|
|
@@ -114,12 +120,14 @@ const grammar = class InstructionMiniparserGrammar {
|
|
|
114
120
|
Tuple(p) {
|
|
115
121
|
p.eat('(', PN, { path: 'openToken', balanced: ')' });
|
|
116
122
|
|
|
117
|
-
let sep
|
|
123
|
+
let sep;
|
|
118
124
|
|
|
119
125
|
let i = 0;
|
|
120
126
|
while (i === 0 || (sep && (p.match(/./y) || p.atExpression))) {
|
|
121
127
|
p.eatProduction('Expression', { path: 'values[]' });
|
|
122
|
-
|
|
128
|
+
if (p.match(/\s*,?/y)) {
|
|
129
|
+
sep = p.eatProduction('Separator', { path: 'separators[]' });
|
|
130
|
+
}
|
|
123
131
|
i++;
|
|
124
132
|
}
|
|
125
133
|
|
|
@@ -131,6 +139,13 @@ const grammar = class InstructionMiniparserGrammar {
|
|
|
131
139
|
p.eat(/true|false/y, KW, { path: 'sigilToken' });
|
|
132
140
|
}
|
|
133
141
|
|
|
142
|
+
//@Node
|
|
143
|
+
Separator(p) {
|
|
144
|
+
p.eatMatchTrivia(_);
|
|
145
|
+
p.eatMatch(/,/y, PN, { path: 'separators[]' });
|
|
146
|
+
p.eatMatchTrivia(_);
|
|
147
|
+
}
|
|
148
|
+
|
|
134
149
|
// @Node
|
|
135
150
|
Null(p) {
|
|
136
151
|
p.eat('null', KW, { path: 'sigilToken' });
|
package/lib/languages/spamex.js
CHANGED
|
@@ -14,18 +14,22 @@ const canonicalURL = 'https://bablr.org/languages/core/en/spamex';
|
|
|
14
14
|
const dependencies = { CSTML, Regex };
|
|
15
15
|
|
|
16
16
|
const covers = buildCovers({
|
|
17
|
-
[sym.node]: [
|
|
17
|
+
[sym.node]: [
|
|
18
|
+
'Attribute',
|
|
19
|
+
'Identifier',
|
|
20
|
+
'Matcher',
|
|
21
|
+
'OpenNodeMatcher',
|
|
22
|
+
'CloseNodeMatcher',
|
|
23
|
+
'Literal',
|
|
24
|
+
'CSTML:Flags',
|
|
25
|
+
],
|
|
18
26
|
Attribute: ['MappingAttribute', 'BooleanAttribute'],
|
|
19
27
|
AttributeValue: ['CSTML:String', 'CSTML:Number'],
|
|
20
|
-
Matcher: ['NodeMatcher', '
|
|
28
|
+
Matcher: ['NodeMatcher', 'StringMatcher'],
|
|
21
29
|
StringMatcher: ['CSTML:String', 'Regex:Pattern'],
|
|
22
30
|
});
|
|
23
31
|
|
|
24
32
|
const grammar = class SpamexMiniparserGrammar {
|
|
25
|
-
Pattern(p) {
|
|
26
|
-
p.eatProduction('Matcher', { path: 'matcher' });
|
|
27
|
-
}
|
|
28
|
-
|
|
29
33
|
// @Cover
|
|
30
34
|
Matcher(p) {
|
|
31
35
|
if (p.match(/<[^!/]/y)) {
|
|
@@ -67,10 +71,8 @@ const grammar = class SpamexMiniparserGrammar {
|
|
|
67
71
|
p.eatProduction('CSTML:Flags', { path: 'flags' });
|
|
68
72
|
}
|
|
69
73
|
|
|
70
|
-
if (p.match(/[a-zA-Z]+:/y)) {
|
|
71
|
-
p.
|
|
72
|
-
p.eat(':', PN, { path: 'namespaceSeparatorToken' });
|
|
73
|
-
p.eat(/[a-zA-Z]+/y, ID, { path: 'type' });
|
|
74
|
+
if (p.match(/['"]|[a-zA-Z]+:/y)) {
|
|
75
|
+
p.eatProduction('CSTML:TagType', { path: 'type' });
|
|
74
76
|
} else if (p.match('?')) {
|
|
75
77
|
p.eat('?', PN, { path: 'type' });
|
|
76
78
|
} else if (p.match(' ')) {
|
package/lib/miniparser.js
CHANGED
|
@@ -9,6 +9,8 @@ const { parsePath } = require('./path.js');
|
|
|
9
9
|
const { set, isRegex, isArray, getPrototypeOf, buildNode } = require('./utils.js');
|
|
10
10
|
const { ReferenceTag, LiteralTag, Escape } = require('@bablr/boot-helpers/symbols');
|
|
11
11
|
|
|
12
|
+
const { hasOwn } = Object;
|
|
13
|
+
|
|
12
14
|
class TemplateParser {
|
|
13
15
|
constructor(rootLanguage, quasis, expressions) {
|
|
14
16
|
if (!quasis) throw new Error();
|
|
@@ -197,6 +199,10 @@ class TemplateParser {
|
|
|
197
199
|
this.spans.push({ type: 'Bare', guard: null });
|
|
198
200
|
}
|
|
199
201
|
|
|
202
|
+
if (!hasOwn(getPrototypeOf(grammar), type)) {
|
|
203
|
+
throw new Error(`Unknown production {type: ${type}}`);
|
|
204
|
+
}
|
|
205
|
+
|
|
200
206
|
const result = getPrototypeOf(grammar)[type].call(grammar, this, props);
|
|
201
207
|
|
|
202
208
|
if (isEmbedded) {
|
|
@@ -319,7 +325,7 @@ class TemplateParser {
|
|
|
319
325
|
|
|
320
326
|
const result = this.matchSticky(pattern, attrs, this);
|
|
321
327
|
|
|
322
|
-
if (!result)
|
|
328
|
+
if (!result) this.fail();
|
|
323
329
|
|
|
324
330
|
this.idx += result.length;
|
|
325
331
|
|
|
@@ -367,7 +373,7 @@ class TemplateParser {
|
|
|
367
373
|
eatTrivia(pattern) {
|
|
368
374
|
const result = this.matchSticky(pattern, {}, this);
|
|
369
375
|
|
|
370
|
-
if (!result)
|
|
376
|
+
if (!result) this.fail();
|
|
371
377
|
|
|
372
378
|
this.idx += result.length;
|
|
373
379
|
|
|
@@ -391,7 +397,7 @@ class TemplateParser {
|
|
|
391
397
|
eatEscape(pattern) {
|
|
392
398
|
const result = this.matchSticky(pattern, {}, this);
|
|
393
399
|
|
|
394
|
-
if (!result)
|
|
400
|
+
if (!result) this.fail();
|
|
395
401
|
|
|
396
402
|
this.idx += result.length;
|
|
397
403
|
|
|
@@ -415,7 +421,7 @@ class TemplateParser {
|
|
|
415
421
|
eatLiteral(pattern) {
|
|
416
422
|
const result = this.matchSticky(pattern, {}, this);
|
|
417
423
|
|
|
418
|
-
if (!result)
|
|
424
|
+
if (!result) this.fail();
|
|
419
425
|
|
|
420
426
|
this.idx += result.length;
|
|
421
427
|
|
|
@@ -451,6 +457,10 @@ class TemplateParser {
|
|
|
451
457
|
this.spans.pop();
|
|
452
458
|
this.spans.push(span);
|
|
453
459
|
}
|
|
460
|
+
|
|
461
|
+
fail() {
|
|
462
|
+
throw new Error(`miniparser: parsing \`${this.quasis}\` failed`);
|
|
463
|
+
}
|
|
454
464
|
}
|
|
455
465
|
|
|
456
466
|
module.exports = { TemplateParser };
|
package/lib/utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/boot",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Compile-time tools for bootstrapping BABLR VM",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=12.0.0"
|
|
7
7
|
},
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
|
-
"require": "./
|
|
11
|
-
"import": "./
|
|
10
|
+
"require": "./dist/cjs.bundle.js",
|
|
11
|
+
"import": "./dist/esm.bundle.js"
|
|
12
12
|
},
|
|
13
13
|
"./shorthand.macro": "./shorthand.macro.js"
|
|
14
14
|
},
|
|
15
|
-
"files": [
|
|
16
|
-
"lib/**/*.js",
|
|
17
|
-
"lib/**/*.mjs",
|
|
18
|
-
"shorthand.macro.js"
|
|
19
|
-
],
|
|
15
|
+
"files": ["lib/**/*.js", "lib/**/*.mjs", "shorthand.macro.js"],
|
|
20
16
|
"sideEffects": false,
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "rollup -c"
|
|
19
|
+
},
|
|
21
20
|
"dependencies": {
|
|
22
21
|
"@babel/helper-module-imports": "^7.22.15",
|
|
23
22
|
"@babel/template": "^7.22.15",
|
|
@@ -26,7 +25,8 @@
|
|
|
26
25
|
"@iter-tools/imm-stack": "1.1.0",
|
|
27
26
|
"escape-string-regexp": "4.0.0",
|
|
28
27
|
"iter-tools": "^7.5.3",
|
|
29
|
-
"jest-diff": "29.7.0"
|
|
28
|
+
"jest-diff": "29.7.0",
|
|
29
|
+
"rollup": "^4.27.3"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@babel/cli": "^7.23.0",
|
|
@@ -34,12 +34,16 @@
|
|
|
34
34
|
"@babel/plugin-proposal-decorators": "^7.23.2",
|
|
35
35
|
"@babel/plugin-transform-runtime": "^7.23.2",
|
|
36
36
|
"@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#a49dbe6861a82d96864ee89fbf0ec1844a8a5e8e",
|
|
37
|
+
"@rollup/plugin-commonjs": "^28.0.1",
|
|
38
|
+
"@rollup/plugin-node-resolve": "^15.3.0",
|
|
37
39
|
"babel-plugin-macros": "^3.1.0",
|
|
38
40
|
"enhanced-resolve": "^5.12.0",
|
|
39
41
|
"eslint": "^8.47.0",
|
|
40
42
|
"eslint-import-resolver-enhanced-resolve": "^1.0.5",
|
|
41
43
|
"eslint-plugin-import": "^2.27.5",
|
|
42
44
|
"expect": "^29.6.2",
|
|
45
|
+
"install": "^0.13.0",
|
|
46
|
+
"npm": "^10.9.0",
|
|
43
47
|
"prettier": "^2.0.5"
|
|
44
48
|
},
|
|
45
49
|
"repository": "git@github.com:bablr-lang/boot.git",
|