@bablr/agast-helpers 0.5.3 → 0.6.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 CHANGED
@@ -1,21 +1,21 @@
1
- import * as sym from './symbols.js';
2
1
  import * as btree from './btree.js';
2
+ import { printType } from './print.js';
3
3
  import {
4
4
  DoctypeTag,
5
5
  OpenNodeTag,
6
6
  CloseNodeTag,
7
- OpenFragmentTag,
8
- CloseFragmentTag,
9
7
  ReferenceTag,
10
8
  ShiftTag,
11
9
  GapTag,
12
10
  NullTag,
13
- ArrayTag,
11
+ ArrayInitializerTag,
14
12
  LiteralTag,
15
- EmbeddedNode,
16
- EmbeddedExpression,
13
+ EmbeddedObject,
17
14
  EmbeddedTag,
18
15
  TokenGroup,
16
+ EmbeddedMatcher,
17
+ EmbeddedRegex,
18
+ EmbeddedNode,
19
19
  } from './symbols.js';
20
20
 
21
21
  const { freeze } = Object;
@@ -26,9 +26,11 @@ const isObject = (val) => val !== null && typeof value !== 'object';
26
26
  function* relatedNodes(properties) {
27
27
  for (const value of Object.values(properties)) {
28
28
  if (isArray(value)) {
29
- yield* btree.traverse(value);
29
+ for (let value of btree.traverse(value)) {
30
+ yield value.node;
31
+ }
30
32
  } else {
31
- yield value;
33
+ yield value.node;
32
34
  }
33
35
  }
34
36
  }
@@ -39,13 +41,28 @@ const find = (predicate, iterable) => {
39
41
  }
40
42
  };
41
43
 
42
- export const buildEmbeddedExpression = (expr) => {
43
- if (!isObject(expr)) return expr;
44
- return freeze({ type: EmbeddedExpression, value: expr });
44
+ export const buildEmbeddedObject = (expr) => {
45
+ if (!isObject(expr)) throw new Error();
46
+ return freeze({ type: EmbeddedObject, value: expr });
47
+ };
48
+
49
+ export const buildEmbeddedNode = (node) => {
50
+ if (!isObject(node)) throw new Error();
51
+ return freeze({ type: EmbeddedNode, value: node });
52
+ };
53
+
54
+ export const buildEmbeddedMatcher = (node) => {
55
+ if (!isObject(node)) throw new Error();
56
+ return freeze({ type: EmbeddedMatcher, value: node });
57
+ };
58
+
59
+ export const buildEmbeddedRegex = (node) => {
60
+ if (!isObject(node)) throw new Error();
61
+ return freeze({ type: EmbeddedRegex, value: node });
45
62
  };
46
63
 
47
64
  export const buildEmbeddedTag = (tag) => {
48
- if (!isObject(tag)) return tag;
65
+ if (!isObject(tag)) throw new Error();
49
66
  return freeze({ type: EmbeddedTag, value: tag });
50
67
  };
51
68
 
@@ -57,18 +74,7 @@ export const buildWriteEffect = (text, options = {}) => {
57
74
  return buildEffect(
58
75
  freeze({
59
76
  verb: 'write',
60
- value: buildEmbeddedExpression(
61
- freeze({ text, options: buildEmbeddedExpression(freeze(options)) }),
62
- ),
63
- }),
64
- );
65
- };
66
-
67
- export const buildYieldEffect = (tag) => {
68
- return buildEffect(
69
- freeze({
70
- verb: 'yield',
71
- value: buildEmbeddedTag(freeze(tag)),
77
+ value: buildEmbeddedObject(freeze({ text, options: buildEmbeddedObject(freeze(options)) })),
72
78
  }),
73
79
  );
74
80
  };
@@ -77,7 +83,7 @@ export const buildAnsiPushEffect = (spans = '') => {
77
83
  return buildEffect(
78
84
  freeze({
79
85
  verb: 'ansi-push',
80
- value: buildEmbeddedExpression(
86
+ value: buildEmbeddedObject(
81
87
  freeze({ spans: spans === '' ? freeze([]) : freeze(spans.split(' ')) }),
82
88
  ),
83
89
  }),
@@ -100,28 +106,27 @@ export const buildBeginningOfStreamToken = () => {
100
106
  return freeze({ type: Symbol.for('@bablr/beginning-of-stream'), value: undefined });
101
107
  };
102
108
 
103
- export const buildReferenceTag = (name, isArray = false, hasGap = false) => {
104
- return freeze({ type: ReferenceTag, value: freeze({ name, isArray, hasGap }) });
109
+ export const buildReferenceTag = (name, isArray = false, flags = referenceFlags, index = null) => {
110
+ if (name == null || !/[a-zA-Z.#@]/.test(name)) throw new Error('reference must have a name');
111
+ if (index != null && !Number.isFinite(index)) throw new Error();
112
+ return freeze({ type: ReferenceTag, value: freeze({ name, isArray, index, flags }) });
105
113
  };
106
114
 
107
115
  export const buildNullTag = () => {
108
116
  return freeze({ type: NullTag, value: undefined });
109
117
  };
110
118
 
111
- export const buildArrayTag = () => {
112
- return freeze({ type: ArrayTag, value: undefined });
119
+ export const buildArrayInitializerTag = () => {
120
+ return freeze({ type: ArrayInitializerTag, value: undefined });
113
121
  };
114
122
 
115
123
  export const buildGapTag = () => {
116
124
  return freeze({ type: GapTag, value: undefined });
117
125
  };
118
126
 
119
- export const buildShiftTag = () => {
120
- return freeze({ type: ShiftTag, value: undefined });
121
- };
122
-
123
- export const buildEmbeddedNode = (node) => {
124
- return freeze({ type: EmbeddedNode, value: node });
127
+ export const buildShiftTag = (index) => {
128
+ if (!Number.isFinite(index)) throw new Error();
129
+ return freeze({ type: ShiftTag, value: freeze({ index }) });
125
130
  };
126
131
 
127
132
  export const buildDoctypeTag = (attributes = {}) => {
@@ -131,37 +136,27 @@ export const buildDoctypeTag = (attributes = {}) => {
131
136
  });
132
137
  };
133
138
 
134
- export const buildNodeOpenTag = (flags = {}, language = null, type = null, attributes = {}) => {
139
+ export const buildOpenNodeTag = (
140
+ flags = nodeFlags,
141
+ language = null,
142
+ type = null,
143
+ attributes = {},
144
+ ) => {
145
+ if (printType(type).startsWith('https://')) throw new Error();
146
+
135
147
  return freeze({
136
148
  type: OpenNodeTag,
137
149
  value: freeze({
138
150
  flags: freeze(flags),
139
151
  language,
140
- type,
152
+ type: isString(type) ? Symbol.for(type) : type,
141
153
  attributes,
142
154
  }),
143
155
  });
144
156
  };
145
157
 
146
- export const buildNodeCloseTag = (type = null, language = null) => {
147
- return freeze({ type: CloseNodeTag, value: freeze({ language, type }) });
148
- };
149
-
150
- export const buildFragmentOpenTag = (flags = {}) => {
151
- return freeze({
152
- type: OpenFragmentTag,
153
- value: freeze({
154
- flags: freeze(flags),
155
- }),
156
- });
157
- };
158
-
159
- export const buildFragmentCloseTag = (type = null, language = null) => {
160
- return freeze({ type: CloseFragmentTag, value: freeze({ language, type }) });
161
- };
162
-
163
- export const wrapFragment = (node) => {
164
- return buildFragment([buildReferenceTag('.')], { '.': node });
158
+ export const buildCloseNodeTag = () => {
159
+ return freeze({ type: CloseNodeTag, value: undefined });
165
160
  };
166
161
 
167
162
  const isString = (val) => typeof val === 'string';
@@ -171,191 +166,50 @@ export const buildLiteralTag = (value) => {
171
166
  return freeze({ type: LiteralTag, value });
172
167
  };
173
168
 
174
- export const buildNodeWithFlags = (
175
- flags,
176
- language,
177
- type,
178
- children = [],
179
- properties = {},
180
- attributes = {},
181
- ) => {
182
- const openTag = buildNodeOpenTag(flags, language, type, attributes);
183
- const closeTag = buildNodeCloseTag(type);
184
-
185
- return freeze({
186
- flags,
187
- language,
188
- type,
189
- children: btree.addAt(0, btree.addAt(btree.getSum(children), children, closeTag), openTag),
190
- properties: freeze(properties),
191
- attributes: freeze(attributes),
192
- });
193
- };
194
-
195
169
  const flagsWithGap = new WeakMap();
196
170
 
197
- export const getFlagsWithGap = (flags) => flagsWithGap.get(flags);
171
+ export const getFlagsWithGap = (flags) => {
172
+ let gapFlags = flagsWithGap.get(flags);
173
+ if (!gapFlags) {
174
+ gapFlags = { ...flags, hasGap: true };
175
+ flagsWithGap.set(flags, gapFlags);
176
+ }
177
+ return gapFlags;
178
+ };
198
179
 
199
180
  export const nodeFlags = freeze({
200
181
  token: false,
201
- escape: false,
202
- trivia: false,
203
- expression: false,
204
182
  hasGap: false,
205
183
  });
206
184
 
207
- const hasGap = (flags, children, properties) => {
185
+ const hasGap = (properties) => {
208
186
  return find((node) => node.flags.hasGap, relatedNodes(properties));
209
187
  };
210
188
 
211
- const getGapFlags = (flags) => {
212
- let gapFlags = flagsWithGap.get(flags);
213
- if (!gapFlags) {
214
- gapFlags = { ...flags, hasGap: true };
215
- flagsWithGap.set(flags, gapFlags);
216
- }
217
- return gapFlags;
218
- };
219
-
220
- const getFlags = (flags, children, properties) => {
221
- if (!hasGap(flags, children, properties)) {
189
+ const getFlags = (flags, properties) => {
190
+ if (!hasGap(properties)) {
222
191
  return flags;
223
192
  } else {
224
- return getGapFlags(flags);
193
+ return getFlagsWithGap(flags);
225
194
  }
226
195
  };
227
196
 
228
- export const buildNode = (language, type, children = [], properties = {}, attributes = {}) => {
229
- const flags = getFlags(nodeFlags, children, properties);
230
- return buildNodeWithFlags(flags, language, type, children, properties, attributes);
231
- };
232
-
233
- export const buildFragmentWithFlags = (flags, children = [], properties = {}, attributes = {}) => {
234
- const doctypeTag = buildDoctypeTag(attributes);
235
- const openTag = buildFragmentOpenTag(flags);
236
- const closeTag = buildFragmentCloseTag();
237
-
238
- return freeze({
239
- flags,
240
- children: btree.addAt(
241
- 0,
242
- btree.addAt(0, btree.addAt(btree.getSum(children), children, closeTag), openTag),
243
- doctypeTag,
244
- ),
245
- properties: freeze(properties),
246
- attributes: freeze(attributes),
247
- });
248
- };
249
-
250
- export const buildFragment = (children = [], properties = {}, attributes = {}) => {
251
- const flags = getFlags(nodeFlags, children, properties);
252
- return buildFragmentWithFlags(flags, children, properties, attributes);
253
- };
254
-
255
- export const syntacticFlags = freeze({
197
+ export const tokenFlags = freeze({
256
198
  token: true,
257
- escape: false,
258
- trivia: false,
259
- expression: false,
260
199
  hasGap: false,
261
200
  });
262
201
 
263
- export const buildSyntacticNode = (language, type, value) => {
264
- return buildNodeWithFlags(syntacticFlags, language, type, [buildLiteralTag(value)]);
265
- };
266
-
267
- export const escapeFlags = freeze({
268
- token: false,
269
- escape: true,
270
- trivia: false,
271
- expression: false,
272
- hasGap: false,
273
- });
274
-
275
- export const buildEscapeNode = (
276
- language,
277
- type,
278
- children = [],
279
- properties = {},
280
- attributes = {},
281
- ) => {
282
- const flags = getFlags(escapeFlags, children, properties);
283
- return buildNodeWithFlags(flags, language, type, children, properties, attributes);
284
- };
285
-
286
- export const syntacticEscapeFlags = freeze({
287
- token: true,
288
- escape: true,
289
- trivia: false,
202
+ export const referenceFlags = freeze({
290
203
  expression: false,
291
204
  hasGap: false,
292
205
  });
293
206
 
294
- export const buildSyntacticEscapeNode = (
295
- language,
296
- type,
297
- children = [],
298
- properties = {},
299
- attributes = {},
300
- ) => {
301
- return buildNodeWithFlags(syntacticEscapeFlags, language, type, children, properties, attributes);
302
- };
303
-
304
- export const syntacticTriviaFlags = freeze({
305
- token: true,
306
- escape: false,
307
- trivia: true,
207
+ export const gapReferenceFlags = freeze({
308
208
  expression: false,
309
- hasGap: false,
209
+ hasGap: true,
310
210
  });
311
211
 
312
- export const buildSyntacticTriviaNode = (
313
- language,
314
- type,
315
- children = [],
316
- properties = {},
317
- attributes = {},
318
- ) => {
319
- return buildNodeWithFlags(syntacticTriviaFlags, language, type, children, properties, attributes);
320
- };
321
-
322
- export const triviaFlags = freeze({
323
- token: false,
324
- escape: false,
325
- trivia: true,
326
- expression: false,
212
+ export const expressionReferenceFlags = freeze({
213
+ expression: true,
327
214
  hasGap: false,
328
215
  });
329
-
330
- export const buildTriviaNode = (
331
- language,
332
- type,
333
- children = [],
334
- properties = {},
335
- attributes = {},
336
- ) => {
337
- const flags = getFlags(triviaFlags, children, properties);
338
- return buildNodeWithFlags(flags, language, type, children, properties, attributes);
339
- };
340
-
341
- export const buildNullNode = (nullToken = buildNullTag()) => {
342
- return freeze({
343
- flags: nodeFlags,
344
- language: null,
345
- type: sym.null,
346
- children: btree.freeze([nullToken]),
347
- properties: freeze({}),
348
- attributes: freeze({}),
349
- });
350
- };
351
-
352
- export const buildGapNode = (gapToken = buildGapTag()) => {
353
- return freeze({
354
- flags: getGapFlags(nodeFlags),
355
- language: null,
356
- type: sym.gap,
357
- children: btree.freeze([gapToken]),
358
- properties: freeze({}),
359
- attributes: freeze({}),
360
- });
361
- };