@bablr/boot 0.10.0 → 0.11.1

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.
@@ -1,12 +1,10 @@
1
- import * as sym from '@bablr/agast-vm-helpers/symbols';
2
- import * as Regex from './regex.js';
3
- import * as CSTML from './cstml.js';
4
- import * as JSON from './json.js';
1
+ import Regex from './regex.js';
2
+ import CSTML from './cstml.js';
3
+ import JSON from './json.js';
5
4
  import { get } from '@bablr/agast-helpers/path';
6
5
 
7
6
  const _ = /\s+/y;
8
- const PN = 'Punctuator';
9
- const ID = 'Identifier';
7
+ const PN = null;
10
8
 
11
9
  export const name = 'Spamex';
12
10
 
@@ -16,85 +14,56 @@ export const dependencies = { CSTML, JSON, Regex };
16
14
 
17
15
  export const covers = new Map([
18
16
  [
19
- sym.node,
17
+ Symbol.for('@bablr/node'),
20
18
  new Set([
21
19
  'CSTML:Identifier',
22
20
  'PropertyMatcher',
23
21
  'JSON:String',
24
22
  'Regex:Pattern',
25
- 'BasicNodeMatcher',
23
+ 'TreeNodeMatcher',
26
24
  'GapNodeMatcher',
27
- 'ArrayNodeMatcher',
28
25
  'NullNodeMatcher',
29
26
  'ReferenceMatcher',
27
+ 'BoundNodeMatcher',
30
28
  'BindingMatcher',
31
- 'OpenNodeMatcher',
32
- 'CloseNodeMatcher',
29
+ 'TreeNodeMatcherOpen',
30
+ 'TreeNodeMatcherClose',
33
31
  'Literal',
34
32
  'CSTML:NodeFlags',
35
33
  ]),
36
34
  ],
37
35
  ['AttributeValue', new Set(['JSON:String', 'CSTML:Number'])],
38
- ['Matcher', new Set(['PropertyMatcher', 'JSON:String', 'Regex:Pattern'])],
39
- [
40
- 'NodeMatcher',
41
- new Set(['BasicNodeMatcher', 'GapNodeMatcher', 'ArrayNodeMatcher', 'NullNodeMatcher']),
42
- ],
36
+ ['Matcher', new Set(['BoundNodeMatcher'])],
37
+ ['NodeMatcher', new Set(['TreeNodeMatcher', 'GapNodeMatcher', 'NullNodeMatcher'])],
43
38
  ['StringMatcher', new Set(['JSON:String', 'Regex:Pattern'])],
44
39
  ]);
45
40
 
46
41
  export const grammar = class SpamexMiniparserGrammar {
47
- // @Cover
48
42
  Matcher(p) {
49
- if (p.match(/[a-zA-Z.#@<:]/y)) {
50
- p.eatProduction('PropertyMatcher');
51
- } else if (p.match(/['"/]/y)) {
52
- p.eatProduction('StringMatcher');
53
- } else {
54
- throw new Error(`Unexpected character ${p.chr}`);
55
- }
43
+ p.eatProduction('BoundNodeMatcher');
56
44
  }
57
45
 
58
- // @Node
59
- // @CoveredBy('NodeMatcher')
60
46
  GapNodeMatcher(p) {
61
47
  p.eat('<//>', PN, { path: 'sigilToken' });
62
48
  }
63
49
 
64
- // @Node
65
- // @CoveredBy('NodeMatcher')
66
- ArrayNodeMatcher(p) {
67
- p.eat('[]', PN, { path: 'sigilToken' });
68
- }
69
-
70
- // @Node
71
- // @CoveredBy('NodeMatcher')
72
50
  NullNodeMatcher(p) {
73
51
  p.eat('null', PN, { path: 'sigilToken' });
74
52
  }
75
53
 
76
- // @Node
77
- // @CoveredBy('Matcher')
78
54
  PropertyMatcher(p) {
79
- if (p.match(/[a-zA-Z.#@]/y)) {
55
+ if (p.match(/[a-zA-Z.#@_]/y) || p.atExpression || null) {
80
56
  p.eatProduction('ReferenceMatcher', { path: 'refMatcher' });
81
57
  }
82
58
 
83
59
  p.eatMatchTrivia(_);
84
60
 
85
- if (p.match(':')) {
86
- p.eatProduction('BindingMatcher', { path: 'bindingMatcher' });
87
- }
88
-
89
- p.eatMatchTrivia(_);
90
-
91
- p.eatProduction('NodeMatcher', { path: 'nodeMatcher' });
61
+ p.eatProduction('BoundNodeMatcher', { path: 'valueMatcher' });
92
62
  }
93
63
 
94
- // @Node
95
64
  ReferenceMatcher(p) {
96
65
  let name, type;
97
- if ((type = p.match(/[.#@]/y))) {
66
+ if ((type = p.match(/\.\.|[.#@_]/y))) {
98
67
  p.eat(type, PN, { path: 'type' });
99
68
  }
100
69
 
@@ -102,50 +71,73 @@ export const grammar = class SpamexMiniparserGrammar {
102
71
  name = p.eatProduction('CSTML:Identifier', { path: 'name' });
103
72
  }
104
73
 
105
- let open =
106
- (name || type) &&
107
- p.eatMatch('[', PN, { path: 'openIndexToken', startSpan: 'Index', balanced: ']' });
108
-
109
- if (open) {
110
- p.eatMatchTrivia(_);
111
- p.eat(']', PN, { path: 'closeIndexToken', endSpan: 'Index', balancer: true });
112
- }
113
-
114
74
  p.eatMatchTrivia(_);
115
- if (p.match(/[+$]/y)) {
75
+ if (!['#', '@'].includes(type)) {
116
76
  p.eatProduction('CSTML:ReferenceFlags', { path: 'flags' });
117
77
  p.eatMatchTrivia(_);
118
78
  }
119
79
  p.eat(':', PN, { path: 'mapToken' });
120
80
  }
121
81
 
122
- // @Node
82
+ BoundNodeMatcher(p) {
83
+ while (p.match(':')) {
84
+ p.eatProduction('BindingMatcher', { path: 'bindingMatchers[]' });
85
+ p.eatMatchTrivia(_);
86
+ }
87
+
88
+ p.eatProduction('NodeMatcher', { path: 'nodeMatcher', noInterpolate: true });
89
+ }
90
+
123
91
  BindingMatcher(p) {
124
92
  p.eat(':', PN, { path: 'openToken' });
93
+
125
94
  p.eatMatchTrivia(_);
126
- p.eatProduction('CSTML:IdentifierPath', { path: 'languagePath' });
127
- p.eatMatchTrivia(_);
95
+ let first = true;
96
+ while (!p.match(':') && (first || p.match('/'))) {
97
+ if (!first) {
98
+ p.eat('/', PN, { path: '#separatorTokens' });
99
+ }
100
+ p.eatProduction('CSTML:BindingSegment', { path: 'segments[]' });
101
+ p.eatMatchTrivia(_);
102
+ first = false;
103
+ }
128
104
  p.eat(':', PN, { path: 'closeToken' });
129
105
  }
130
106
 
131
107
  NodeMatcher(p) {
132
- if (p.match('<//>')) {
133
- p.eatProduction('GapNodeMatcher');
134
- } else if (p.match('<')) {
135
- p.eatProduction('BasicNodeMatcher');
136
- } else if (p.match('[')) {
137
- p.eatProduction('ArrayNodeMatcher');
138
- } else if (p.match('null')) {
139
- p.eatProduction('NullNodeMatcher');
140
- } else {
141
- p.fail();
108
+ let chrs = p.match(/<\/\/?>|<|null/y);
109
+ switch (chrs) {
110
+ case '<//>':
111
+ p.eatProduction('GapNodeMatcher');
112
+ break;
113
+ case '</>':
114
+ p.fail();
115
+ break;
116
+ case 'null':
117
+ p.eatProduction('NullNodeMatcher');
118
+ break;
119
+ default:
120
+ p.eatProduction('TreeNodeMatcher', { noInterpolate: true });
121
+ break;
142
122
  }
143
123
  }
144
124
 
145
- // @Node
146
- // @CoveredBy('NodeMatcher')
147
- BasicNodeMatcher(p) {
148
- let open = p.eatProduction('OpenNodeMatcher', { path: 'open' });
125
+ TreeNodeMatcher(p) {
126
+ if (p.match(/['"/]/y)) {
127
+ do {
128
+ p.eatProduction('StringMatcher', { path: 'children[]' });
129
+ p.eatMatchTrivia(_);
130
+ } while (p.match(/['"/]/y));
131
+
132
+ return;
133
+ }
134
+
135
+ if (p.match(/[a-zA-Z.#@]/y) || p.atExpression) {
136
+ p.eatProduction('PropertyMatcher', { path: 'children[]', noInterpolate: true });
137
+ return;
138
+ }
139
+
140
+ let open = p.eatProduction('TreeNodeMatcherOpen', { path: 'open' });
149
141
 
150
142
  if (!get('selfClosingToken', open)) {
151
143
  p.eatMatchTrivia(_);
@@ -160,24 +152,24 @@ export const grammar = class SpamexMiniparserGrammar {
160
152
  // }
161
153
  }
162
154
 
163
- p.eatProduction('CloseNodeMatcher', { path: 'close' });
155
+ p.eatProduction('TreeNodeMatcherClose', { path: 'close' });
164
156
  }
165
157
  }
166
158
 
167
- // @Node
168
- OpenNodeMatcher(p) {
169
- p.eat('<', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
159
+ TreeNodeMatcherOpen(p) {
160
+ p.eat('<', PN, { path: 'openToken' });
170
161
 
171
162
  if (!p.atExpression) {
172
163
  p.eatProduction('CSTML:NodeFlags', { path: 'flags' });
173
164
  }
174
165
 
166
+ let type;
167
+ if ((type = p.match(/[?]|__?/y))) {
168
+ p.eat(type, PN, { path: 'type' });
169
+ }
170
+
175
171
  if (p.match(/[a-zA-Z]/y) || p.atExpression) {
176
- p.eatProduction('CSTML:Identifier', { path: 'type' });
177
- } else if (p.match('?')) {
178
- p.eat('?', PN, { path: 'type' });
179
- } else if (p.match('_')) {
180
- p.eat('_', PN, { path: 'type' });
172
+ p.eatProduction('CSTML:Identifier', { path: 'name' });
181
173
  }
182
174
 
183
175
  let sp = p.eatMatchTrivia(_);
@@ -194,16 +186,17 @@ export const grammar = class SpamexMiniparserGrammar {
194
186
  }
195
187
 
196
188
  p.eatMatchTrivia(_);
197
- p.eatMatch('/', PN, { path: 'selfClosingToken' });
198
- p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
189
+ let sc = p.eatMatch('/', PN, { path: 'selfClosingToken' });
190
+ p.eat('>', PN, { path: 'closeToken' });
191
+
192
+ return { attrs: { selfClosing: !!sc } };
199
193
  }
200
194
 
201
- CloseNodeMatcher(p) {
202
- p.eat('</', PN, { path: 'openToken', startSpan: 'Tag', balanced: '>' });
203
- p.eat('>', PN, { path: 'closeToken', endSpan: 'Tag', balancer: true });
195
+ TreeNodeMatcherClose(p) {
196
+ p.eat('</', PN, { path: 'openToken' });
197
+ p.eat('>', PN, { path: 'closeToken' });
204
198
  }
205
199
 
206
- // @Cover
207
200
  StringMatcher(p) {
208
201
  if (p.match(/['"]/y)) {
209
202
  p.eatProduction('JSON:String');
@@ -212,3 +205,5 @@ export const grammar = class SpamexMiniparserGrammar {
212
205
  }
213
206
  }
214
207
  };
208
+
209
+ export default { name, canonicalURL, dependencies, covers, grammar };
package/lib/match.js CHANGED
@@ -1,7 +1,8 @@
1
- import { createNode } from '@bablr/agast-helpers/tree';
2
1
  import { Path } from './path.js';
3
2
  import { resolveDependentLanguage } from './utils.js';
4
3
  import * as sym from '@bablr/agast-vm-helpers/symbols';
4
+ import { buildOpenCoverTag, buildOpenNodeTag, nodeFlags } from '@bablr/agast-helpers/builders';
5
+ import { buildNode } from '@bablr/agast-helpers/path';
5
6
 
6
7
  export class Match {
7
8
  constructor(parent, resolvedLanguage, id, attributes, path) {
@@ -18,10 +19,10 @@ export class Match {
18
19
  }
19
20
 
20
21
  get isNode() {
21
- const { type, resolvedLanguage } = this;
22
+ const { name, resolvedLanguage } = this;
22
23
  const { covers } = resolvedLanguage;
23
24
 
24
- return covers.get(sym.node).has(type) && !covers.has(type);
25
+ return covers.get(Symbol.for('@bablr/node')).has(name) && !covers.has(name);
25
26
  }
26
27
 
27
28
  get language() {
@@ -32,6 +33,10 @@ export class Match {
32
33
  return this.id.type;
33
34
  }
34
35
 
36
+ get name() {
37
+ return this.id.name;
38
+ }
39
+
35
40
  get attrs() {
36
41
  return this.attributes;
37
42
  }
@@ -39,20 +44,19 @@ export class Match {
39
44
  static from(language, id, attrs = {}) {
40
45
  const resolvedLanguage = resolveDependentLanguage(language, id.language);
41
46
  const { covers } = resolvedLanguage;
42
- const { type } = id;
43
- const isCover = covers.has(type);
44
- const isNode = covers.get(sym.node).has(type);
47
+ const { name } = id;
48
+ const isCover = covers.has(name);
49
+ const isNode = covers.get(Symbol.for('@bablr/node')).has(name);
45
50
 
46
51
  if (!isNode && !isCover) {
47
- throw new Error(`Top {type: ${type}} must be a node or fragment`);
52
+ throw new Error(`Top {type: ${name}} must be a node or fragment`);
48
53
  }
49
54
 
50
55
  const path = Path.from(id, attrs);
51
56
 
52
- if (isNode && !isCover) {
53
- path.node = createNode();
54
- path.node.type = Symbol.for(type);
55
- }
57
+ path.node = buildNode(
58
+ isCover ? buildOpenCoverTag(nodeFlags, name) : buildOpenNodeTag(nodeFlags, name),
59
+ );
56
60
 
57
61
  return new Match(null, resolvedLanguage, id, attrs, path);
58
62
  }
@@ -60,9 +64,9 @@ export class Match {
60
64
  generate(id, attrs) {
61
65
  const resolvedLanguage = resolveDependentLanguage(this.resolvedLanguage, id.language);
62
66
  const { covers } = resolvedLanguage;
63
- const { type } = id;
64
- const isCover = covers.has(type);
65
- const isNode = covers.get(sym.node).has(type) && !isCover;
67
+ const { name } = id;
68
+ const isCover = covers.has(name);
69
+ const isNode = covers.get(Symbol.for('@bablr/node')).has(name) && !isCover;
66
70
 
67
71
  const baseAttrs = this.isNode ? {} : this.attrs;
68
72
 
@@ -75,8 +79,7 @@ export class Match {
75
79
  } else {
76
80
  path = path.generate(id, attrs);
77
81
  }
78
- path.node = createNode();
79
- path.node.type = Symbol.for(type);
82
+ path.node = buildNode(buildOpenNodeTag(nodeFlags, name));
80
83
  }
81
84
 
82
85
  return new Match(this, resolvedLanguage, id, { ...baseAttrs, ...attrs }, path);