@bablr/agast-helpers 0.11.3 → 0.11.4

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,7 +1,6 @@
1
1
  import * as BList from './b-list.js';
2
2
  import { hasOwn, isObject, isArray, isSymbol, isString, isFrozen, freezeRecord } from './object.js';
3
3
  import { buildParser, match } from './parse.js';
4
- import { printExpression, printTag } from './print.js';
5
4
 
6
5
  import {
7
6
  DoctypeTag,
@@ -19,7 +18,7 @@ import {
19
18
  NullNode,
20
19
  GapNode,
21
20
  TreeNode,
22
- StreamTag,
21
+ MuxerTag,
23
22
  } from './symbols.js';
24
23
 
25
24
  export const symbolName = (name) => {
@@ -144,17 +143,15 @@ export const buildBindingTag = (type, name) => {
144
143
  return buildTag(BindingTag, buildBinding(type, name));
145
144
  };
146
145
 
147
- export const buildStreamTag = (processPath, stream) => {
146
+ export const buildMuxerTag = (processPath, stream) => {
148
147
  if (stream && !(stream >= 1 && stream <= 4)) throw new Error();
149
148
 
150
- return buildTag(StreamTag, { processPath, stream });
149
+ return buildTag(MuxerTag, { processPath, stream });
151
150
  };
152
151
 
153
152
  export const buildChild = (type, value) => {
154
153
  if (!isSymbol(type)) throw new Error();
155
- let child = buildTag(type, value);
156
- if (!parseTag(child)) throw new Error();
157
- return child;
154
+ return buildTag(type, value);
158
155
  };
159
156
 
160
157
  export const buildGapTag = () => {
@@ -325,10 +322,10 @@ export const canContinueIdentifier = (chr) => {
325
322
  };
326
323
 
327
324
  export const parseTagType = (input) => {
325
+ if (isObject(input) && input.type) return input.type;
328
326
  let p = buildTagParser(input);
329
327
  let { str, idx } = p;
330
328
  if (str == null) return null;
331
- if (isObject(str)) return str.type;
332
329
  if (!isString(str)) throw new Error();
333
330
  if (!str.length) throw new Error();
334
331
 
@@ -348,7 +345,7 @@ export const parseTagType = (input) => {
348
345
  ? GapTag
349
346
  : CloseNodeTag
350
347
  : str[idx + 1] === '-'
351
- ? StreamTag
348
+ ? MuxerTag
352
349
  : OpenNodeTag;
353
350
  case '^':
354
351
  return ShiftTag;
@@ -373,6 +370,30 @@ export const parseTagType = (input) => {
373
370
  }
374
371
  };
375
372
 
373
+ export const parseStreamTagType = (input) => {
374
+ if (isObject(input) && input.type) return input.type;
375
+ let p = buildTagParser(input);
376
+ let { str, idx } = p;
377
+ if (str == null) return null;
378
+ if (!isString(str)) throw new Error();
379
+ if (!str.length) throw new Error();
380
+
381
+ if (str[idx] === '<') {
382
+ if (str[idx + 1] === '-') {
383
+ if (str[idx + 2] === '-') {
384
+ return parseTagType(input);
385
+ } else {
386
+ return MuxerTag;
387
+ }
388
+ throw new Error('reserved syntax');
389
+ } else {
390
+ return parseTagType(input);
391
+ }
392
+ } else {
393
+ return parseTagType(input);
394
+ }
395
+ };
396
+
376
397
  export const parseObject = (input) => {
377
398
  let p = buildParser(input);
378
399
  let { str } = p;
@@ -567,7 +588,7 @@ export const parseNumber = (input) => {
567
588
 
568
589
  let endIdx = p.idx;
569
590
 
570
- return parseFloat(str.slice(startIdx, endIdx));
591
+ return parseFloat([...str.slice(startIdx, endIdx)].join(''));
571
592
  };
572
593
 
573
594
  export const parseEscape = (input) => {
@@ -760,8 +781,7 @@ let buildTagParser = (tag) => {
760
781
  return { idx: 0, str: tag };
761
782
  case 'object':
762
783
  if (tag.type) {
763
- // TODO str is sometimes not a string!
764
- return { idx: 0, str: typeof tag === 'string' ? tag : printTag(tag) };
784
+ throw new Error();
765
785
  } else {
766
786
  return tag;
767
787
  }
@@ -818,11 +838,15 @@ export const parseOpenNodeTag = (tag) => {
818
838
  while (chr === ' ') chr = str[++p.idx];
819
839
  }
820
840
 
821
- let attributes = freezeRecord({});
841
+ let attributes = '{}';
822
842
 
823
843
  if (chr === '{') {
824
- attributes = parseObject(p);
844
+ let startIdx = p.idx;
845
+ parseObject(p);
846
+ let endIdx = p.idx;
825
847
  chr = str[p.idx];
848
+ // prevent attributes causing a memory leak on the original string
849
+ attributes = [...str.slice(startIdx, endIdx)].join('');
826
850
 
827
851
  while (chr === ' ') chr = str[++p.idx];
828
852
  }
@@ -847,7 +871,7 @@ export const parseOpenNodeTag = (tag) => {
847
871
  name: symbolName(name),
848
872
  type: symbolName(type),
849
873
  literalValue,
850
- attributes: printExpression(attributes),
874
+ attributes,
851
875
  selfClosing,
852
876
  });
853
877
  };
@@ -898,6 +922,14 @@ export const parseReferenceTag = (tag) => {
898
922
  chr = str[++p.idx];
899
923
  }
900
924
 
925
+ if (type === '.' && chr === '.') {
926
+ type = '..';
927
+ chr = str[++p.idx];
928
+ } else if (type === '_' && chr === '_') {
929
+ type = '__';
930
+ chr = str[++p.idx];
931
+ }
932
+
901
933
  let quotedIdent = chr === '`';
902
934
  if (!type || (type === '#' && canStartIdentifier(chr))) {
903
935
  name = parseIdentifier(p);
@@ -1061,10 +1093,14 @@ export const parseDoctypeTag = (tag) => {
1061
1093
  chr = str[++p.idx];
1062
1094
  }
1063
1095
 
1064
- let attributes = {};
1096
+ let attributes = '{}';
1097
+
1065
1098
  if (chr === '{') {
1066
- attributes = parseObject(p);
1099
+ let startIdx = p.idx;
1100
+ parseObject(p);
1101
+ let endIdx = p.idx;
1067
1102
  chr = str[p.idx];
1103
+ attributes = [...str.slice(startIdx, endIdx)].join('');
1068
1104
 
1069
1105
  while (chr === ' ') chr = str[++p.idx];
1070
1106
  }
@@ -1074,10 +1110,10 @@ export const parseDoctypeTag = (tag) => {
1074
1110
 
1075
1111
  if (isString(tag) && p.idx !== p.str.length) throw new Error();
1076
1112
 
1077
- return buildDoctypeTag(version, printExpression(attributes));
1113
+ return buildDoctypeTag(version, attributes);
1078
1114
  };
1079
1115
 
1080
- export const parseStreamTag = (tag) => {
1116
+ export const parseMuxerTag = (tag) => {
1081
1117
  let p = buildTagParser(tag);
1082
1118
  let { str } = p;
1083
1119
  let chr = str[p.idx];
@@ -1110,10 +1146,12 @@ export const parseStreamTag = (tag) => {
1110
1146
  if (chr !== '>') throw new Error();
1111
1147
  chr = str[++p.idx];
1112
1148
 
1113
- return buildStreamTag(processPath, stream);
1149
+ return buildMuxerTag(processPath, stream);
1114
1150
  };
1115
1151
 
1116
1152
  export const parseTag = (tag) => {
1153
+ if (isObject(tag) && tag.type === Property) return tag;
1154
+
1117
1155
  let p = buildTagParser(tag);
1118
1156
  if (tag == null) return null;
1119
1157
 
@@ -1134,8 +1172,6 @@ export const parseTag = (tag) => {
1134
1172
  return parseLiteralTag(tag);
1135
1173
  case CloseNodeTag:
1136
1174
  return parseCloseNodeTag(tag);
1137
- case StreamTag:
1138
- return parseStreamTag(tag);
1139
1175
  case GapTag:
1140
1176
  return parseGapTag(tag);
1141
1177
  case NullTag:
@@ -1152,6 +1188,16 @@ export const parseTag = (tag) => {
1152
1188
  }
1153
1189
  };
1154
1190
 
1191
+ export const parseStreamTag = (tag) => {
1192
+ if (isObject(tag) && tag.type === Property) return tag;
1193
+ let p = buildTagParser(tag);
1194
+ if (tag == null) return null;
1195
+
1196
+ let tagType = parseStreamTagType(p);
1197
+
1198
+ return tagType === MuxerTag ? parseMuxerTag(tag) : parseTag(tag);
1199
+ };
1200
+
1155
1201
  export const isValidTag = (tag) => {
1156
1202
  if (isString(tag)) return !!parseTag(tag);
1157
1203
  if (!isFrozen(tag)) return false;
package/lib/path.js CHANGED
@@ -210,7 +210,7 @@ export const nodeIsComplete = (node) => {
210
210
  };
211
211
 
212
212
  export const offsetForTag = (tag) => {
213
- switch (parseTagType(tag)) {
213
+ switch (isString(tag) ? parseTagType(tag) : tag) {
214
214
  case ReferenceTag:
215
215
  case ShiftTag:
216
216
  return [0];
@@ -396,7 +396,7 @@ export const has = (path, node) => {
396
396
  path = [path];
397
397
  }
398
398
 
399
- let pathArr = [...path];
399
+ let pathArr = [...arrayValues(path)];
400
400
  let node_ = get(pathArr.slice(0, -1), node);
401
401
  let seg = pathArr[pathArr.length - 1];
402
402
 
@@ -1005,7 +1005,10 @@ export const Path = class AgastPath {
1005
1005
  [
1006
1006
  firstTag,
1007
1007
  Tags.fromValues(
1008
- map((binding) => buildChild(BindingTag, binding), arrayValues(targetBindings)),
1008
+ map(
1009
+ (binding) => printTag(buildChild(BindingTag, binding)),
1010
+ arrayValues(targetBindings),
1011
+ ),
1009
1012
  ),
1010
1013
  value,
1011
1014
  ],
@@ -1128,7 +1131,10 @@ export const Path = class AgastPath {
1128
1131
  [
1129
1132
  firstTag,
1130
1133
  Tags.fromValues(
1131
- map((binding) => buildChild(BindingTag, binding), arrayValues(targetBindings)),
1134
+ map(
1135
+ (binding) => printTag(buildChild(BindingTag, binding)),
1136
+ arrayValues(targetBindings),
1137
+ ),
1132
1138
  ),
1133
1139
  value,
1134
1140
  ],
@@ -1249,7 +1255,7 @@ export const Path = class AgastPath {
1249
1255
 
1250
1256
  let { tags } = tagPath.value;
1251
1257
 
1252
- if (tags[1][0]?.type === ShiftTag && !tags[1][2]) {
1258
+ if (parseTagType(tags[1][0]) === ShiftTag && !tags[1][2]) {
1253
1259
  return TagPath.from(tagPath.path, tagPath.tagsIndex - 1).value;
1254
1260
  }
1255
1261
 
@@ -1389,8 +1395,8 @@ export const Path = class AgastPath {
1389
1395
  refPath = TagPath.from(refPath.path, refPath.tagsIndex - shift.index, 0);
1390
1396
  }
1391
1397
 
1392
- let { 0: firstTag, 1: bindingTags = [] } = propPath.value.tags[1];
1393
- let tags = BList.fromValues([firstTag, Tags.from(...bindingTags, tag_)], 1);
1398
+ let { 0: firstTag, 1: bindingTags = BList.fromValues([]) } = propPath.value.tags[1];
1399
+ let tags = BList.fromValues([firstTag, Tags.push(tag, bindingTags)], 1);
1394
1400
  let property = buildChild(Property, buildProperty(tags, shift));
1395
1401
 
1396
1402
  targetPath = this.replaceWith(
@@ -1472,7 +1478,7 @@ export const Path = class AgastPath {
1472
1478
  if (!openTag) throw new Error();
1473
1479
  if (parseTag(openTag).value.selfClosing) throw new Error();
1474
1480
 
1475
- targetPath = targetPath.replaceWith(buildNode(Tags.push(tag_, getTags(node))));
1481
+ targetPath = targetPath.replaceWith(buildNode(Tags.push(tag, getTags(node))));
1476
1482
  break;
1477
1483
  }
1478
1484
 
@@ -1580,7 +1586,7 @@ export const Path = class AgastPath {
1580
1586
  let newOpenTag = buildOpenNodeTag(flags, name, null, printObject(attributes));
1581
1587
 
1582
1588
  targetPath = this.replaceWith(
1583
- buildNode(Tags.push(tag_, Tags.replaceAt(0, newOpenTag, getTags(node)))),
1589
+ buildNode(Tags.push(tag, Tags.replaceAt(0, printTag(newOpenTag), getTags(node)))),
1584
1590
  );
1585
1591
  break;
1586
1592
  }
@@ -1611,7 +1617,7 @@ export const Path = class AgastPath {
1611
1617
  case LiteralTag:
1612
1618
  if (typeof tag_.value !== 'string') throw new Error();
1613
1619
 
1614
- targetPath = this.replaceWith(buildNode(Tags.push(tag_, this.node.value.tags)));
1620
+ targetPath = this.replaceWith(buildNode(Tags.push(tag, this.node.value.tags)));
1615
1621
  break;
1616
1622
 
1617
1623
  default:
@@ -1784,6 +1790,10 @@ export class TagPath {
1784
1790
  return this.path.depth;
1785
1791
  }
1786
1792
 
1793
+ atDepth(depth) {
1794
+ return this.path.atDepth(depth);
1795
+ }
1796
+
1787
1797
  siblingAt(index) {
1788
1798
  return TagPath.from(this.path, index);
1789
1799
  }
package/lib/print.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  LiteralTag,
11
11
  AttributeDefinition,
12
12
  BindingTag,
13
- StreamTag,
13
+ MuxerTag,
14
14
  } from './symbols.js';
15
15
  import { parseObject } from './builders.js';
16
16
  import { arrayValues } from './iterable.js';
@@ -131,7 +131,7 @@ export const printReference = (ref) => {
131
131
  let { type, name, flags } = ref;
132
132
 
133
133
  if (type && type !== '#' && name) throw new Error();
134
- if (type && !['_', '.', '#', '@'].includes(type)) throw new Error();
134
+ if (type && !['_', '__', '.', '..', '#', '@'].includes(type)) throw new Error();
135
135
 
136
136
  return `${type || ''}${printIdentifier(name) || ''}${printReferenceFlags(flags)}:`;
137
137
  };
@@ -253,8 +253,8 @@ export const printSelfClosingNodeTag = (tag, literalValue) => {
253
253
  return `<${printNodeFlags(flags)}${typeFrag}${nameFrag}${literalFrag}${attributesFrag} />`;
254
254
  };
255
255
 
256
- export const printStreamTag = (tag) => {
257
- if (tag?.type !== StreamTag) throw new Error();
256
+ export const printMuxerTag = (tag) => {
257
+ if (tag?.type !== MuxerTag) throw new Error();
258
258
 
259
259
  let { processPath, stream } = tag.value;
260
260
 
@@ -287,7 +287,7 @@ const printers = {
287
287
  [ReferenceTag]: printReferenceTag,
288
288
  [OpenNodeTag]: printOpenNodeTag,
289
289
  [CloseNodeTag]: printCloseNodeTag,
290
- [StreamTag]: printStreamTag,
290
+ [MuxerTag]: printMuxerTag,
291
291
  [AttributeDefinition]: printAttributeDefinition,
292
292
  };
293
293
 
@@ -304,8 +304,8 @@ export const printIOTag = (tag) => {
304
304
  if (tag == null || isString(tag)) return tag;
305
305
  if (!isObject(tag)) throw new Error();
306
306
 
307
- if (tag.type === StreamTag) {
308
- return printStreamTag(tag);
307
+ if (tag.type === MuxerTag) {
308
+ return printMuxerTag(tag);
309
309
  }
310
310
  return printTag(tag);
311
311
  };
package/lib/stream.js CHANGED
@@ -5,7 +5,6 @@ import {
5
5
  StreamIterable,
6
6
  StreamGenerator,
7
7
  wait,
8
- createDeferred,
9
8
  continue_,
10
9
  } from '@bablr/stream-iterator';
11
10
  import * as Tags from './tags.js';
@@ -19,6 +18,7 @@ import {
19
18
  buildProperty,
20
19
  buildReference,
21
20
  parseTag,
21
+ parseStreamTag,
22
22
  parseTagType,
23
23
  } from './builders.js';
24
24
  import {
@@ -32,11 +32,10 @@ import {
32
32
  DoctypeTag,
33
33
  ShiftTag,
34
34
  AttributeDefinition,
35
- StreamTag,
35
+ MuxerTag,
36
36
  } from './symbols.js';
37
- import { buildNode, getRoot, isGapNode, isNode, Path } from './path.js';
38
- import { streamFromTree } from './tree.js';
39
- import { freeze, isObject } from './object.js';
37
+ import { buildNode, getRoot, isGapNode, isNode, Path, TagPath } from './path.js';
38
+ import { freeze, isPlainObject } from './object.js';
40
39
  import { maybeWait } from './iterable.js';
41
40
  import { arrayValues } from '@bablr/record';
42
41
  import { buildParser } from './parse.js';
@@ -139,8 +138,7 @@ function* __treeFromStream(tags, options) {
139
138
  }
140
139
 
141
140
  export const treeFromStream = (tags, options = freeze({})) => {
142
- let iter = new StreamGenerator(__treeFromStream(tags, options));
143
- return maybeWait(iter.next(), (step) => step.value);
141
+ return evaluateReturn(__treeFromStream(tags, options));
144
142
  };
145
143
 
146
144
  function* __isEmpty(tags) {
@@ -280,7 +278,7 @@ export const generateCSTML = (tags, options = freeze({})) =>
280
278
  new StreamIterable(__generateCSTML(tags, options));
281
279
 
282
280
  const isToken = (tag) => {
283
- return parseTag(tag).value.flags.token;
281
+ return tag.value.flags.token;
284
282
  };
285
283
 
286
284
  export const prettyGroupTags = (tags) => new StreamIterable(__prettyGroupTags(tags));
@@ -300,8 +298,9 @@ function* __prettyGroupTags(tags) {
300
298
  }
301
299
  if (step.done) break;
302
300
 
303
- const tag = parseTag(step.value);
304
- const isOpenClose = tag.type === CloseNodeTag || tag.type === OpenNodeTag;
301
+ let tag_ = step.value;
302
+ let tag = parseTag(tag_);
303
+ let isOpenClose = tag.type === CloseNodeTag || tag.type === OpenNodeTag;
305
304
 
306
305
  if (
307
306
  (tag.type === 'Effect' && tag.value.verb === 'write') ||
@@ -323,28 +322,28 @@ function* __prettyGroupTags(tags) {
323
322
  state.holding = [];
324
323
  }
325
324
  } else if (tag.type === LiteralTag) {
326
- state.holding.push(tag);
325
+ state.holding.push(tag_);
327
326
  }
328
327
 
329
328
  if (!state.holding.length && !isOpenClose) {
330
- yield tag;
329
+ yield step.value;
331
330
  }
332
331
 
333
332
  if (tag.type === CloseNodeTag) {
334
333
  if (!state.broken && (isToken(state.open) || state.holding.length === 1)) {
335
- let { flags, name, attributes } = state.holding[0].value;
334
+ let { flags, name, attributes } = parseTag(state.holding[0]).value;
336
335
 
337
336
  let literal = state.holding
338
337
  .slice(1)
339
- .map((lit) => lit.value)
338
+ .map((lit) => parseTag(lit).value)
340
339
  .join('');
341
340
 
342
- yield buildOpenNodeTag(flags, name, literal, attributes, true);
341
+ yield printTag(buildOpenNodeTag(flags, name, literal, attributes, true));
343
342
  } else {
344
343
  if (state.holding.length) {
345
344
  yield* state.holding;
346
345
  }
347
- yield tag;
346
+ yield step.value;
348
347
  }
349
348
 
350
349
  states = states.pop();
@@ -353,9 +352,9 @@ function* __prettyGroupTags(tags) {
353
352
 
354
353
  if (tag.type === OpenNodeTag) {
355
354
  if (tag.value.selfClosing) {
356
- yield tag;
355
+ yield step.value;
357
356
  } else {
358
- states = states.push({ holding: [tag], broken: false, open: tag });
357
+ states = states.push({ holding: [tag_], broken: false, open: tag });
359
358
 
360
359
  state = states.value;
361
360
  }
@@ -379,9 +378,9 @@ function* __transformStream(tags, stream, strategy) {
379
378
  }
380
379
  if (step.done) break;
381
380
 
382
- let tag = parseTag(step.value);
381
+ let tag = parseStreamTag(step.value);
383
382
 
384
- if (tag.type === StreamTag) {
383
+ if (tag.type === MuxerTag) {
385
384
  if (tag.value.stream !== stream) {
386
385
  transforming = false;
387
386
  yield continue_();
@@ -410,7 +409,7 @@ function* __transformStream(tags, stream, strategy) {
410
409
  }
411
410
  if (step.done) break;
412
411
 
413
- let tag = parseTag(step.value);
412
+ let tag = parseStreamTag(step.value);
414
413
 
415
414
  if (transforming) {
416
415
  strategyStep = strategyIter.next();
@@ -425,8 +424,8 @@ function* __transformStream(tags, stream, strategy) {
425
424
  }
426
425
  }
427
426
  if (step.done) break;
428
- tag = parseTag(step.value);
429
- if (tag.type === StreamTag) {
427
+ tag = parseStreamTag(step.value);
428
+ if (tag.type === MuxerTag) {
430
429
  stream_ = tag.value.stream;
431
430
  } else {
432
431
  throw new Error();
@@ -434,7 +433,7 @@ function* __transformStream(tags, stream, strategy) {
434
433
  yield step.value;
435
434
  transforming = stream_ === stream;
436
435
  } else {
437
- if (tag.type === StreamTag) {
436
+ if (tag.type === MuxerTag) {
438
437
  stream_ = tag.value.stream;
439
438
 
440
439
  yield step.value;
@@ -456,6 +455,85 @@ export const transformStream = (tags, stream, strategy) => {
456
455
  return new StreamIterable(__transformStream(tags, stream, strategy));
457
456
  };
458
457
 
458
+ function* __transformStreams(tags, strategy) {
459
+ let iter = getStreamIterator(tags);
460
+ let step;
461
+ let str = '';
462
+ let streamTag = '<-1>';
463
+ let alreadyAdvanced = false;
464
+ let strategyStep;
465
+ let streams = new Map();
466
+
467
+ function* __streamTags(streamTag) {
468
+ for (;;) {
469
+ while (step === null || step instanceof Promise) {
470
+ if (step === null) yield continue_(), (step = iter.next());
471
+ if (step instanceof Promise) step = yield wait(step);
472
+ }
473
+ if (step.done) break;
474
+
475
+ let tag = parseStreamTag(step.value);
476
+
477
+ if (tag.type === MuxerTag) {
478
+ if (printTag(streamTag) !== printTag(tag)) {
479
+ yield continue_();
480
+ }
481
+
482
+ streamTag = step.value;
483
+ } else {
484
+ yield step.value;
485
+ }
486
+
487
+ step = iter.next();
488
+ }
489
+ }
490
+
491
+ for (;;) {
492
+ if (!alreadyAdvanced) {
493
+ step = iter.next();
494
+ }
495
+ alreadyAdvanced = false;
496
+ while (step === null || step instanceof Promise) {
497
+ if (step === null) yield continue_(), (step = iter.next());
498
+ if (step instanceof Promise) step = yield wait(step);
499
+ }
500
+ if (step.done) break;
501
+
502
+ let tag = parseStreamTag(step.value);
503
+
504
+ streams[streamTag] ||= getStreamIterator(
505
+ strategy(new StreamGenerator(__streamTags(parseStreamTag(streamTag)))),
506
+ );
507
+
508
+ strategyStep = streams[streamTag].next();
509
+
510
+ while (strategyStep !== null) {
511
+ if (strategyStep instanceof Promise) strategyStep = yield wait(strategyStep);
512
+ if (strategyStep) {
513
+ if (strategyStep.done) break;
514
+ yield strategyStep.value;
515
+
516
+ strategyStep = streams[streamTag].next();
517
+ }
518
+ }
519
+ if (step.done) break;
520
+ tag = parseStreamTag(step.value);
521
+ if (tag.type === MuxerTag) {
522
+ streamTag = step.value;
523
+
524
+ yield step.value;
525
+
526
+ alreadyAdvanced = true;
527
+ } else {
528
+ throw new Error();
529
+ }
530
+ }
531
+ }
532
+
533
+ export const transformStreams = (tags, strategy) => {
534
+ return new StreamIterable(__transformStreams(tags, strategy));
535
+ };
536
+
459
537
  let pushFrame = (parent = null) => {
460
538
  let heldProperties = parent ? [...parent.heldProperties] : [];
461
539
  if (parent) {
@@ -487,16 +565,61 @@ let popFrame = (frame) => {
487
565
  return frame.parent;
488
566
  };
489
567
 
568
+ export const streamFromTree = (tree, options = freeze({})) => {
569
+ if (tree && !isPlainObject(tree)) throw new Error();
570
+
571
+ return __streamFromTree(null, tree, options);
572
+ };
573
+
574
+ function* __streamFromTree(doctypeTag, rootNode, options) {
575
+ const { unshift = false, getGapNode, checkBalance = true } = options;
576
+ if (!rootNode || !Tags.getSize(Tags.getTags(rootNode))) return;
577
+
578
+ let tagPath = TagPath.fromNode(rootNode, 0);
579
+ let count = 0;
580
+ let stack = [{ tagPath, count }];
581
+
582
+ if (doctypeTag) {
583
+ yield doctypeTag;
584
+ }
585
+
586
+ do {
587
+ ({ tagPath, count } = stack.pop());
588
+ do {
589
+ if (tagPath.type === OpenNodeTag && !tagPath.value.selfClosing) count++;
590
+ if (tagPath.type === CloseNodeTag) count--;
591
+
592
+ let gapNode;
593
+ if (
594
+ getGapNode &&
595
+ tagPath.type === GapTag &&
596
+ (gapNode = getGapNode(tagPath.path.node)) &&
597
+ gapNode !== tagPath.path.node
598
+ ) {
599
+ stack.push({ tagPath: unshift ? tagPath.nextUnshifted : tagPath.next, count });
600
+ tagPath = TagPath.fromNode(gapNode, 0);
601
+ count = 0;
602
+ }
603
+
604
+ if (!(tagPath.type === AttributeDefinition)) {
605
+ yield tagPath.tag;
606
+ }
607
+ } while ((tagPath = unshift ? tagPath.nextUnshifted : tagPath.next));
608
+ } while (stack.length);
609
+
610
+ if (checkBalance && count !== 0) throw new Error();
611
+ }
612
+
490
613
  function* emitHeld(frame, nextTag) {
491
614
  if (frame.ref?.flags.expression && nextTag?.type === ShiftTag) return;
492
615
 
493
616
  for (let property of frame.heldProperties) {
494
617
  let { reference, bindings, node } = property;
495
- yield buildChild(ReferenceTag, reference);
618
+ yield printTag(buildChild(ReferenceTag, reference));
496
619
  let isAnonymous = node.value.flags.token && !node.value.name;
497
620
  if (!isAnonymous) {
498
621
  for (let binding of arrayValues(bindings)) {
499
- yield buildChild(BindingTag, binding);
622
+ yield printTag(buildChild(BindingTag, binding));
500
623
  }
501
624
  }
502
625
  yield* streamFromTree(node);
@@ -625,11 +748,11 @@ function* __hoistTrivia(co, firstTag) {
625
748
  }
626
749
  } else if (frame && !isCover) {
627
750
  if (!frame.shifting && ((frame.ref && frame.ref.type !== '_') || frame.expanded)) {
628
- yield buildChild(ReferenceTag, frame.ref);
751
+ yield printTag(buildChild(ReferenceTag, frame.ref));
629
752
  let isAnonymous = tag.value.flags.token && !tag.value.name;
630
753
  if (!isAnonymous) {
631
754
  for (let binding of frame.bindings) {
632
- yield buildChild(BindingTag, binding);
755
+ yield printTag(buildChild(BindingTag, binding));
633
756
  }
634
757
  }
635
758
  }
@@ -665,15 +788,15 @@ function* __hoistTrivia(co, firstTag) {
665
788
  frame = popFrame(frame);
666
789
 
667
790
  if (!frame) {
668
- yield tag;
791
+ yield printTag(tag);
669
792
 
670
793
  break;
671
794
  } else {
672
- yield tag;
795
+ yield printTag(tag);
673
796
  }
674
797
  } else {
675
798
  if (!isCover || !parentFrame) {
676
- yield tag;
799
+ yield printTag(tag);
677
800
  }
678
801
  }
679
802
  }
@@ -697,7 +820,7 @@ function* __hoistTrivia(co, firstTag) {
697
820
  frame.expanded = frame.depth === 1 && frame.coverDepth === 1;
698
821
 
699
822
  if (tag.value.type === '_' && parentFrame.expanded && parentFrame.depth) {
700
- yield tag;
823
+ yield printTag(tag);
701
824
  }
702
825
  } else if (tag.type === ShiftTag) {
703
826
  let doneFrame = frame;
@@ -710,7 +833,7 @@ function* __hoistTrivia(co, firstTag) {
710
833
  frame.shifting = true;
711
834
  // frame.heldProperties = [...doneFrame.heldProperties];
712
835
 
713
- yield tag;
836
+ yield printTag(tag);
714
837
  } else if (tag.type === BindingTag) {
715
838
  let { heldProperties } = frame;
716
839
  if (heldProperties.length) {
@@ -721,7 +844,7 @@ function* __hoistTrivia(co, firstTag) {
721
844
  BList.fromValues(
722
845
  [
723
846
  tags[1][0] || Tags.fromValues([]),
724
- Tags.push(tag, tags[1][1] || Tags.fromValues([])),
847
+ Tags.push(printTag(tag), tags[1][1] || Tags.fromValues([])),
725
848
  ],
726
849
  1,
727
850
  ),
@@ -749,33 +872,33 @@ function* __hoistTrivia(co, firstTag) {
749
872
  if (frame) {
750
873
  frame.heldProperties = [...lastFrame.heldProperties];
751
874
  if (!lastFrame?.coverDepth) {
752
- yield tag;
875
+ yield printTag(tag);
753
876
  }
754
877
  } else {
755
878
  if (lastFrame.expanded || lastFrame.open.value.type !== Symbol.for('_')) {
756
- yield tag;
879
+ yield printTag(tag);
757
880
  }
758
881
  break;
759
882
  }
760
883
  } else if (tag.type === GapTag || tag.type === NullTag) {
761
884
  if (frame.ref) {
762
- yield buildChild(ReferenceTag, frame.ref);
885
+ yield printTag(buildChild(ReferenceTag, frame.ref));
763
886
  }
764
887
  lastFrame = frame;
765
888
 
766
889
  frame = popFrame(frame);
767
890
 
768
891
  if (tag.type === GapTag && frame.heldProperties.length) {
769
- yield tag;
892
+ yield printTag(tag);
770
893
 
771
894
  frame.shifting = false;
772
895
 
773
896
  yield* emitHeld(frame, nextTag);
774
897
  } else {
775
- yield tag;
898
+ yield printTag(tag);
776
899
  }
777
900
  } else {
778
- yield tag;
901
+ yield printTag(tag);
779
902
  }
780
903
 
781
904
  tag = nextTag;
package/lib/symbols.js CHANGED
@@ -5,7 +5,7 @@ export const ReferenceTag = Symbol.for('ReferenceTag');
5
5
  export const ShiftTag = Symbol.for('ShiftTag');
6
6
  export const GapTag = Symbol.for('GapTag');
7
7
  export const BindingTag = Symbol.for('BindingTag');
8
- export const StreamTag = Symbol.for('StreamTag');
8
+ export const MuxerTag = Symbol.for('MuxerTag');
9
9
  export const NullTag = Symbol.for('NullTag');
10
10
  export const AttributeDefinition = Symbol.for('AttributeDefinition');
11
11
  export const LiteralTag = Symbol.for('LiteralTag');
package/lib/tags.js CHANGED
@@ -273,6 +273,7 @@ export const sumValues = (values, depth) => {
273
273
  types: freezeRecord(
274
274
  [...mapStats.types.values()].sort((a, b) => compareNames(a[0], b[0])).flatMap((_) => _),
275
275
  ),
276
+ hashes: null,
276
277
  });
277
278
  return stats;
278
279
  };
package/lib/tree.js CHANGED
@@ -1,10 +1,7 @@
1
1
  import {
2
2
  buildOpenNodeTag,
3
- buildCloseNodeTag,
4
3
  tokenFlags,
5
4
  buildChild,
6
- buildGapTag,
7
- buildOpenFragmentTag,
8
5
  buildReference,
9
6
  parseTagType,
10
7
  parseTag,
@@ -17,6 +14,7 @@ import {
17
14
  evaluateReturn,
18
15
  printOpenNodeTag,
19
16
  streamFromString,
17
+ streamFromTree,
20
18
  } from './stream.js';
21
19
  import {
22
20
  OpenNodeTag,
@@ -24,13 +22,8 @@ import {
24
22
  ReferenceTag,
25
23
  GapTag,
26
24
  LiteralTag,
27
- AttributeDefinition,
28
25
  BindingTag,
29
- ShiftTag,
30
26
  Property,
31
- NullNode,
32
- TreeNode,
33
- GapNode,
34
27
  } from './symbols.js';
35
28
  import * as Tags from './tags.js';
36
29
  export * from './builders.js';
@@ -40,7 +33,6 @@ import {
40
33
  getOr,
41
34
  has,
42
35
  list,
43
- TagPath,
44
36
  isCover,
45
37
  isNullNode,
46
38
  isGapNode,
@@ -48,7 +40,7 @@ import {
48
40
  getCloseNodeTag,
49
41
  getRoot,
50
42
  } from './path.js';
51
- import { freeze, freezeRecord, isPlainObject } from './object.js';
43
+ import { freeze, freezeRecord } from './object.js';
52
44
 
53
45
  export {
54
46
  get,
@@ -136,149 +128,6 @@ export const isEmpty = (node) => {
136
128
  return true;
137
129
  };
138
130
 
139
- export const streamFromTree = (tree, options = freeze({})) => {
140
- if (tree && !isPlainObject(tree)) throw new Error();
141
-
142
- return __streamFromTree(null, tree, options);
143
- };
144
-
145
- function* __streamFromTree(doctypeTag, rootNode, options) {
146
- const { unshift = false, getGapNode, checkBalance = true } = options;
147
- if (!rootNode || !Tags.getSize(getTags(rootNode))) return;
148
-
149
- let tagPath = TagPath.fromNode(rootNode, 0);
150
- let count = 0;
151
- let stack = [{ tagPath, count }];
152
-
153
- if (doctypeTag) {
154
- yield doctypeTag;
155
- }
156
-
157
- do {
158
- ({ tagPath, count } = stack.pop());
159
- do {
160
- if (tagPath.type === OpenNodeTag && !tagPath.value.selfClosing) count++;
161
- if (tagPath.type === CloseNodeTag) count--;
162
-
163
- let gapNode;
164
- if (
165
- getGapNode &&
166
- tagPath.type === GapTag &&
167
- (gapNode = getGapNode(tagPath.path.node)) &&
168
- gapNode !== tagPath.path.node
169
- ) {
170
- stack.push({ tagPath: unshift ? tagPath.nextUnshifted : tagPath.next, count });
171
- tagPath = TagPath.fromNode(gapNode, 0);
172
- count = 0;
173
- }
174
-
175
- if (!(tagPath.type === AttributeDefinition)) {
176
- yield tagPath.tag;
177
- }
178
- } while ((tagPath = unshift ? tagPath.nextUnshifted : tagPath.next));
179
- } while (stack.length);
180
-
181
- if (checkBalance && count !== 0) throw new Error();
182
- }
183
-
184
- export const vcsStreamFromTree = (rootNode) => {
185
- return __vcsStreamFromTree(rootNode);
186
- };
187
-
188
- function* __vcsStreamFromTree(rootNode) {
189
- let stack = null;
190
- let agastNode = rootNode;
191
- let depth = 0;
192
- let nodeShifted = false;
193
- let i = 0;
194
- let seenFirstProperty = false;
195
- let node = Tags.getValues(rootNode.value.tags);
196
-
197
- outer: while (node) {
198
- while (i >= node.length) {
199
- if (stack) {
200
- let oldAgastNode = agastNode;
201
- let hadSeenFirst = seenFirstProperty;
202
- ({ stack, agastNode, node, depth, i, nodeShifted, seenFirstProperty } = stack);
203
- if (oldAgastNode === agastNode) {
204
- seenFirstProperty = hadSeenFirst;
205
- yield buildCloseNodeTag();
206
- }
207
-
208
- i++;
209
- } else {
210
- return;
211
- }
212
- }
213
-
214
- let child = node[i];
215
-
216
- if (isArray(child)) {
217
- stack = { stack, agastNode, node, depth, i, nodeShifted, seenFirstProperty };
218
-
219
- yield buildOpenFragmentTag();
220
-
221
- node = Tags.getValues(child);
222
- depth++;
223
- i = 0;
224
- } else {
225
- let wrappedTag = child;
226
-
227
- let wrappedType = parseTagType(wrappedTag);
228
-
229
- if (wrappedType === Property) {
230
- for (let tag of wrappedTag.value.tags) {
231
- let tagType = parseTagType(tag);
232
- switch (tagType) {
233
- case TreeNode:
234
- case NullNode:
235
- case GapNode: {
236
- let replaceWithGap = nodeShifted && !seenFirstProperty;
237
-
238
- if (replaceWithGap) {
239
- yield buildGapTag();
240
-
241
- seenFirstProperty = true;
242
-
243
- break;
244
- } else {
245
- stack = { stack, agastNode, node, depth, i, nodeShifted, seenFirstProperty: true };
246
- node = Tags.getValues(tag.value.tags);
247
-
248
- depth++;
249
- i = 0;
250
- agastNode = tag;
251
- nodeShifted = wrappedTag.value.tags[0].type === ShiftTag;
252
- seenFirstProperty = false;
253
- continue outer;
254
- }
255
- }
256
-
257
- default: {
258
- yield tag;
259
-
260
- if (tagType === OpenNodeTag && parseTag(tag).value.literalValue) {
261
- ({ stack, agastNode, node, depth, i, nodeShifted } = stack);
262
- seenFirstProperty = true;
263
- }
264
-
265
- break;
266
- }
267
- }
268
- }
269
- } else {
270
- yield wrappedTag;
271
-
272
- if (wrappedType === OpenNodeTag && wrappedTag.value.literalValue) {
273
- ({ stack, agastNode, node, depth, i, nodeShifted } = stack);
274
- seenFirstProperty = true;
275
- }
276
- }
277
- i++;
278
- }
279
- }
280
- }
281
-
282
131
  export const getCooked = (cookable) => {
283
132
  if (!cookable || isGapNode(cookable)) {
284
133
  return '';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bablr/agast-helpers",
3
3
  "description": "Helper functions for working with agAST trees",
4
- "version": "0.11.3",
4
+ "version": "0.11.4",
5
5
  "author": "Conrad Buck<conartist6@gmail.com>",
6
6
  "type": "module",
7
7
  "files": [
package/lib/spans.js DELETED
File without changes