@traqula/core 0.0.18 → 0.0.20

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.
Files changed (36) hide show
  1. package/lib/AstCoreFactory.js +1 -1
  2. package/lib/AstCoreFactory.js.map +1 -1
  3. package/lib/TransformerObject.d.ts +64 -0
  4. package/lib/TransformerObject.js +204 -0
  5. package/lib/TransformerObject.js.map +1 -0
  6. package/lib/TransformerSubTyped.d.ts +94 -0
  7. package/lib/TransformerSubTyped.js +116 -0
  8. package/lib/TransformerSubTyped.js.map +1 -0
  9. package/lib/TransformerTyped.d.ts +62 -0
  10. package/lib/TransformerTyped.js +95 -0
  11. package/lib/TransformerTyped.js.map +1 -0
  12. package/lib/generator-builder/dynamicGenerator.d.ts +13 -3
  13. package/lib/generator-builder/dynamicGenerator.js +90 -60
  14. package/lib/generator-builder/dynamicGenerator.js.map +1 -1
  15. package/lib/generator-builder/generatorBuilder.d.ts +5 -2
  16. package/lib/generator-builder/generatorBuilder.js +6 -3
  17. package/lib/generator-builder/generatorBuilder.js.map +1 -1
  18. package/lib/generator-builder/generatorTypes.d.ts +35 -21
  19. package/lib/generator-builder/generatorTypes.js.map +1 -1
  20. package/lib/index.cjs +346 -138
  21. package/lib/index.d.ts +3 -1
  22. package/lib/index.js +3 -1
  23. package/lib/index.js.map +1 -1
  24. package/lib/indirection-builder/IndirBuilder.d.ts +4 -1
  25. package/lib/indirection-builder/IndirBuilder.js +6 -3
  26. package/lib/indirection-builder/IndirBuilder.js.map +1 -1
  27. package/lib/parser-builder/parserBuilder.d.ts +12 -8
  28. package/lib/parser-builder/parserBuilder.js +6 -3
  29. package/lib/parser-builder/parserBuilder.js.map +1 -1
  30. package/lib/utils.d.ts +4 -0
  31. package/lib/utils.js +4 -0
  32. package/lib/utils.js.map +1 -1
  33. package/package.json +2 -2
  34. package/lib/Transformers.d.ts +0 -129
  35. package/lib/Transformers.js +0 -226
  36. package/lib/Transformers.js.map +0 -1
package/lib/index.cjs CHANGED
@@ -25,8 +25,9 @@ __export(index_exports, {
25
25
  IndirBuilder: () => IndirBuilder,
26
26
  LexerBuilder: () => LexerBuilder,
27
27
  ParserBuilder: () => ParserBuilder,
28
- TransformerSubType: () => TransformerSubType,
29
- TransformerType: () => TransformerType,
28
+ TransformerObject: () => TransformerObject,
29
+ TransformerSubTyped: () => TransformerSubTyped,
30
+ TransformerTyped: () => TransformerTyped,
30
31
  createToken: () => createToken2,
31
32
  listToIndirectionMap: () => listToIndirectionMap,
32
33
  traqulaIndentation: () => traqulaIndentation,
@@ -51,7 +52,7 @@ var AstCoreFactory = class {
51
52
  if (filtered.length === 0) {
52
53
  return this.gen();
53
54
  }
54
- const first2 = filtered[0];
55
+ const first2 = filtered.at(0);
55
56
  const last2 = filtered.at(-1);
56
57
  return {
57
58
  sourceLocationType: "source",
@@ -1526,8 +1527,8 @@ var Promise2 = getNative_default(root_default, "Promise");
1526
1527
  var Promise_default = Promise2;
1527
1528
 
1528
1529
  // ../../node_modules/lodash-es/_Set.js
1529
- var Set2 = getNative_default(root_default, "Set");
1530
- var Set_default = Set2;
1530
+ var Set = getNative_default(root_default, "Set");
1531
+ var Set_default = Set;
1531
1532
 
1532
1533
  // ../../node_modules/lodash-es/_getTag.js
1533
1534
  var mapTag2 = "[object Map]";
@@ -9395,13 +9396,16 @@ var DynamicGenerator = class {
9395
9396
  __context = void 0;
9396
9397
  origSource = "";
9397
9398
  generatedUntil = 0;
9398
- expectsSpace;
9399
+ toEnsure = [];
9400
+ /**
9401
+ * Should not contain empty strings
9402
+ * @protected
9403
+ */
9399
9404
  stringBuilder = [];
9400
9405
  constructor(rules) {
9401
9406
  this.rules = rules;
9402
9407
  for (const rule of Object.values(rules)) {
9403
9408
  this[rule.name] = ((input, context, args) => {
9404
- this.expectsSpace = false;
9405
9409
  this.stringBuilder.length = 0;
9406
9410
  this.origSource = context.origSource;
9407
9411
  this.generatedUntil = context?.offset ?? 0;
@@ -9426,12 +9430,15 @@ var DynamicGenerator = class {
9426
9430
  const generate = () => def.gImpl({
9427
9431
  SUBRULE: this.subrule,
9428
9432
  PRINT: this.print,
9429
- PRINT_SPACE_LEFT: this.printSpaceLeft,
9433
+ ENSURE: this.ensure,
9434
+ ENSURE_EITHER: this.ensureEither,
9435
+ NEW_LINE: this.newLine,
9436
+ HANDLE_LOC: this.handleLoc,
9437
+ CATCHUP: this.catchup,
9430
9438
  PRINT_WORD: this.printWord,
9431
9439
  PRINT_WORDS: this.printWords,
9432
9440
  PRINT_ON_EMPTY: this.printOnEmpty,
9433
- CATCHUP: this.catchup,
9434
- HANDLE_LOC: this.handleLoc
9441
+ PRINT_ON_OWN_LINE: this.printOnOwnLine
9435
9442
  })(ast, this.getSafeContext(), ...arg);
9436
9443
  if (this.factory.isLocalized(ast)) {
9437
9444
  this.handleLoc(ast, generate);
@@ -9469,43 +9476,82 @@ var DynamicGenerator = class {
9469
9476
  }
9470
9477
  this.generatedUntil = Math.max(this.generatedUntil, until);
9471
9478
  };
9479
+ handeEnsured(toPrint) {
9480
+ for (const callBack of this.toEnsure) {
9481
+ callBack(toPrint);
9482
+ }
9483
+ this.toEnsure.length = 0;
9484
+ }
9472
9485
  print = (...args) => {
9473
- const pureArgs = args.filter((x) => x.length > 0);
9474
- if (pureArgs.length > 0) {
9475
- const head2 = pureArgs[0];
9476
- if (this.expectsSpace) {
9477
- this.expectsSpace = false;
9478
- const blanks = /* @__PURE__ */ new Set(["\n", " ", " "]);
9479
- if (this.stringBuilder.length > 0 && !(blanks.has(head2[0]) || blanks.has(this.stringBuilder.at(-1).at(-1)))) {
9480
- this.stringBuilder.push(" ");
9486
+ const joined = args.join("");
9487
+ this.handeEnsured(joined);
9488
+ this.stringBuilder.push(joined);
9489
+ };
9490
+ doesEndWith(subsStr) {
9491
+ const len = subsStr.length;
9492
+ let temp = "";
9493
+ while (temp.length < len && this.stringBuilder.length > 0) {
9494
+ temp = this.stringBuilder.pop() + temp;
9495
+ }
9496
+ this.stringBuilder.push(temp);
9497
+ return temp.endsWith(subsStr);
9498
+ }
9499
+ ensure = (...args) => {
9500
+ const toEnsure = args.join("");
9501
+ if (!this.doesEndWith(toEnsure)) {
9502
+ this.toEnsure.push((willPrint) => {
9503
+ if (!willPrint.startsWith(toEnsure) && !this.doesEndWith(toEnsure)) {
9504
+ this.stringBuilder.push(toEnsure);
9481
9505
  }
9482
- }
9483
- const context = this.getSafeContext();
9484
- if (context[traqulaIndentation] && typeof context[traqulaIndentation] === "number") {
9485
- const indent = context[traqulaIndentation];
9486
- for (const str of pureArgs) {
9487
- const [noNl, ...postNl] = str.split("\n");
9488
- this.stringBuilder.push(noNl);
9489
- for (const subStr of postNl.map((line) => line.trimStart())) {
9490
- this.stringBuilder.push("\n", " ".repeat(indent));
9491
- if (subStr.length > 0) {
9492
- this.stringBuilder.push(subStr);
9493
- }
9494
- }
9506
+ });
9507
+ }
9508
+ };
9509
+ ensureEither = (...args) => {
9510
+ if (args.length === 1) {
9511
+ this.ensure(...args);
9512
+ } else if (args.length > 1 && // Not already matched?
9513
+ !args.some((subStr) => this.doesEndWith(subStr))) {
9514
+ this.toEnsure.push((willPrint) => {
9515
+ if (!args.some((subStr) => willPrint.startsWith(subStr)) && !args.some((subStr) => this.doesEndWith(subStr))) {
9516
+ this.stringBuilder.push(args[0]);
9495
9517
  }
9518
+ });
9519
+ }
9520
+ };
9521
+ pruneEndingBlanks() {
9522
+ let temp = "";
9523
+ while (/^[ \t]*$/u.test(temp) && this.stringBuilder.length > 0) {
9524
+ temp = this.stringBuilder.pop() + temp;
9525
+ }
9526
+ this.print(temp.trimEnd());
9527
+ }
9528
+ newLine = (arg) => {
9529
+ const indentation = this.getSafeContext()[traqulaIndentation] ?? 0;
9530
+ if (indentation === -1) {
9531
+ return;
9532
+ }
9533
+ const force = arg?.force ?? false;
9534
+ this.pruneEndingBlanks();
9535
+ if (force) {
9536
+ this.print("\n", " ".repeat(indentation));
9537
+ } else {
9538
+ let temp = "";
9539
+ while (!temp.includes("\n") && this.stringBuilder.length > 0) {
9540
+ temp = this.stringBuilder.pop() + temp;
9541
+ }
9542
+ if (/\n[ \t]*$/u.test(temp)) {
9543
+ temp = temp.replace(/\n[ \t]*$/u, `
9544
+ ${" ".repeat(indentation)}`);
9545
+ this.print(temp);
9496
9546
  } else {
9497
- this.stringBuilder.push(...pureArgs);
9547
+ this.print(temp, "\n", " ".repeat(indentation));
9498
9548
  }
9499
9549
  }
9500
9550
  };
9501
9551
  printWord = (...args) => {
9502
- this.expectsSpace = true;
9503
- this.print(...args);
9504
- this.expectsSpace = true;
9505
- };
9506
- printSpaceLeft = (...args) => {
9507
- this.expectsSpace = true;
9552
+ this.ensureEither(" ", "\n");
9508
9553
  this.print(...args);
9554
+ this.ensureEither(" ", "\n");
9509
9555
  };
9510
9556
  printWords = (...args) => {
9511
9557
  for (const arg of args) {
@@ -9513,28 +9559,13 @@ var DynamicGenerator = class {
9513
9559
  }
9514
9560
  };
9515
9561
  printOnEmpty = (...args) => {
9516
- let counter = this.stringBuilder.length - 1;
9517
- let onEmpty = true;
9518
- const isEmptyTest = /^[ \t\n]*$/u;
9519
- while (counter >= 0 && onEmpty) {
9520
- const cur = this.stringBuilder[counter];
9521
- const indexOfNl = cur.lastIndexOf("\n");
9522
- if (indexOfNl >= 0) {
9523
- onEmpty = isEmptyTest.test(cur.slice(indexOfNl));
9524
- if (onEmpty) {
9525
- const newVal = cur.slice(0, indexOfNl);
9526
- if (newVal) {
9527
- this.stringBuilder[counter] = cur.slice(0, indexOfNl);
9528
- } else {
9529
- this.stringBuilder.splice(counter, 1);
9530
- }
9531
- }
9532
- break;
9533
- }
9534
- onEmpty = isEmptyTest.test(cur);
9535
- counter--;
9536
- }
9537
- this.print("\n", ...args);
9562
+ this.newLine();
9563
+ this.print(...args);
9564
+ };
9565
+ printOnOwnLine = (...args) => {
9566
+ this.newLine();
9567
+ this.print(...args);
9568
+ this.newLine();
9538
9569
  };
9539
9570
  };
9540
9571
 
@@ -9548,10 +9579,10 @@ function listToRuleDefMap(rules) {
9548
9579
  }
9549
9580
  var GeneratorBuilder = class _GeneratorBuilder {
9550
9581
  static create(start) {
9551
- if (start instanceof _GeneratorBuilder) {
9552
- return new _GeneratorBuilder({ ...start.rules });
9582
+ if (Array.isArray(start)) {
9583
+ return new _GeneratorBuilder(listToRuleDefMap(start));
9553
9584
  }
9554
- return new _GeneratorBuilder(listToRuleDefMap(start));
9585
+ return new _GeneratorBuilder({ ...start.rules });
9555
9586
  }
9556
9587
  rules;
9557
9588
  constructor(startRules) {
@@ -9600,6 +9631,9 @@ var GeneratorBuilder = class _GeneratorBuilder {
9600
9631
  delete this.rules[ruleName];
9601
9632
  return this;
9602
9633
  }
9634
+ getRule(ruleName) {
9635
+ return this.rules[ruleName];
9636
+ }
9603
9637
  /**
9604
9638
  * Merge this grammar GeneratorBuilder with another.
9605
9639
  * It is best to merge the bigger grammar with the smaller one.
@@ -9677,10 +9711,10 @@ var DynamicIndirect = class {
9677
9711
  // lib/indirection-builder/IndirBuilder.js
9678
9712
  var IndirBuilder = class _IndirBuilder {
9679
9713
  static create(start) {
9680
- if (start instanceof _IndirBuilder) {
9681
- return new _IndirBuilder({ ...start.rules });
9714
+ if (Array.isArray(start)) {
9715
+ return new _IndirBuilder(listToIndirectionMap(start));
9682
9716
  }
9683
- return new _IndirBuilder(listToIndirectionMap(start));
9717
+ return new _IndirBuilder({ ...start.rules });
9684
9718
  }
9685
9719
  rules;
9686
9720
  constructor(startRules) {
@@ -9729,6 +9763,9 @@ var IndirBuilder = class _IndirBuilder {
9729
9763
  delete this.rules[ruleName];
9730
9764
  return this;
9731
9765
  }
9766
+ getRule(ruleName) {
9767
+ return this.rules[ruleName];
9768
+ }
9732
9769
  build() {
9733
9770
  return new DynamicIndirect(this.rules);
9734
9771
  }
@@ -9958,10 +9995,10 @@ var ParserBuilder = class _ParserBuilder {
9958
9995
  * If a builder is provided, a new copy will be created.
9959
9996
  */
9960
9997
  static create(start) {
9961
- if (start instanceof _ParserBuilder) {
9962
- return new _ParserBuilder({ ...start.rules });
9998
+ if (Array.isArray(start)) {
9999
+ return new _ParserBuilder(listToRuleDefMap2(start));
9963
10000
  }
9964
- return new _ParserBuilder(listToRuleDefMap2(start));
10001
+ return new _ParserBuilder({ ...start.rules });
9965
10002
  }
9966
10003
  rules;
9967
10004
  constructor(startRules) {
@@ -10010,6 +10047,9 @@ var ParserBuilder = class _ParserBuilder {
10010
10047
  delete this.rules[ruleName];
10011
10048
  return this;
10012
10049
  }
10050
+ getRule(ruleName) {
10051
+ return this.rules[ruleName];
10052
+ }
10013
10053
  /**
10014
10054
  * Merge this grammar builder with another.
10015
10055
  * It is best to merge the bigger grammar with the smaller one.
@@ -10096,21 +10136,31 @@ ${firstError.message}`);
10096
10136
  }
10097
10137
  };
10098
10138
 
10099
- // lib/Transformers.js
10100
- var TransformerType = class {
10101
- clone(obj) {
10102
- const newObj = Object.create(Object.getPrototypeOf(obj));
10103
- Object.defineProperties(newObj, Object.getOwnPropertyDescriptors(obj));
10104
- return newObj;
10139
+ // lib/TransformerObject.js
10140
+ var TransformerObject = class {
10141
+ defaultContext;
10142
+ maxStackSize = 1e6;
10143
+ /**
10144
+ * Creates stateless transformer.
10145
+ * @param defaultContext
10146
+ */
10147
+ constructor(defaultContext = {}) {
10148
+ this.defaultContext = defaultContext;
10105
10149
  }
10106
- safeObjectVisit(value, mapper) {
10107
- if (value && typeof value === "object") {
10108
- if (Array.isArray(value)) {
10109
- return value.map((x) => this.safeObjectVisit(x, mapper));
10110
- }
10111
- return mapper(value);
10150
+ /**
10151
+ * Function to shallow clone any type.
10152
+ * @param obj
10153
+ * @protected
10154
+ */
10155
+ clone(obj) {
10156
+ if (obj === null || typeof obj !== "object") {
10157
+ return obj;
10112
10158
  }
10113
- return value;
10159
+ const proto = Object.getPrototypeOf(obj);
10160
+ if (proto === Object.prototype || proto === null) {
10161
+ return { ...obj };
10162
+ }
10163
+ return Object.assign(Object.create(proto), obj);
10114
10164
  }
10115
10165
  /**
10116
10166
  * Recursively transforms all objects that are not arrays. Mapper is called on deeper objects first.
@@ -10122,90 +10172,228 @@ var TransformerType = class {
10122
10172
  * - Default false
10123
10173
  */
10124
10174
  transformObject(startObject, mapper, preVisitor = () => ({})) {
10175
+ const defaults2 = this.defaultContext;
10176
+ const defaultCopyFlag = defaults2.copy ?? true;
10177
+ const defaultContinues = defaults2.continue ?? true;
10178
+ const defaultIgnoreKeys = defaults2.ignoreKeys;
10179
+ const defaultShallowKeys = defaults2.shallowKeys;
10180
+ const defaultDidShortCut = defaults2.shortcut ?? false;
10125
10181
  let didShortCut = false;
10126
- const recurse = (curObject) => {
10127
- const copy = this.clone(curObject);
10128
- const context = preVisitor(copy);
10129
- didShortCut = context.shortcut ?? false;
10130
- const continues = context.continue ?? true;
10131
- if (continues && !didShortCut) {
10132
- for (const [key, value] of Object.entries(copy)) {
10133
- if (didShortCut) {
10134
- return copy;
10182
+ const resultWrap = { res: startObject };
10183
+ const stack = [startObject];
10184
+ const stackParent = [resultWrap];
10185
+ const stackParentKey = ["res"];
10186
+ const handleMapperOnLen = [];
10187
+ const mapperCopyStack = [];
10188
+ const mapperOrigStack = [];
10189
+ const mapperParent = [];
10190
+ const mapperParentKey = [];
10191
+ function handleMapper() {
10192
+ while (stack.length === handleMapperOnLen.at(-1)) {
10193
+ handleMapperOnLen.pop();
10194
+ const copyToMap = mapperCopyStack.pop();
10195
+ const origToMap = mapperOrigStack.pop();
10196
+ const parent = mapperParent.pop();
10197
+ const parentKey = mapperParentKey.pop();
10198
+ parent[parentKey] = mapper(copyToMap, origToMap);
10199
+ }
10200
+ }
10201
+ while (stack.length > 0 && stack.length < this.maxStackSize) {
10202
+ const curObject = stack.pop();
10203
+ const curParent = stackParent.pop();
10204
+ const curKey = stackParentKey.pop();
10205
+ if (!didShortCut) {
10206
+ if (Array.isArray(curObject)) {
10207
+ const newArr = [...curObject];
10208
+ handleMapperOnLen.push(stack.length);
10209
+ mapperCopyStack.push(newArr);
10210
+ mapperOrigStack.push(curObject);
10211
+ mapperParent.push(curParent);
10212
+ mapperParentKey.push(curKey);
10213
+ for (let index = curObject.length - 1; index >= 0; index--) {
10214
+ const val = curObject[index];
10215
+ if (val !== null && typeof val === "object") {
10216
+ stack.push(val);
10217
+ stackParent.push(newArr);
10218
+ stackParentKey.push(index.toString());
10219
+ }
10220
+ }
10221
+ handleMapper();
10222
+ continue;
10223
+ }
10224
+ const context = preVisitor(curObject);
10225
+ const copyFlag = context.copy ?? defaultCopyFlag;
10226
+ const continues = context.continue ?? defaultContinues;
10227
+ const ignoreKeys = context.ignoreKeys ?? defaultIgnoreKeys;
10228
+ const shallowKeys = context.shallowKeys ?? defaultShallowKeys;
10229
+ didShortCut = context.shortcut ?? defaultDidShortCut;
10230
+ const copy = copyFlag ? this.clone(curObject) : curObject;
10231
+ handleMapperOnLen.push(stack.length);
10232
+ mapperCopyStack.push(copy);
10233
+ mapperOrigStack.push(curObject);
10234
+ mapperParent.push(curParent);
10235
+ mapperParentKey.push(curKey);
10236
+ if (continues && !didShortCut) {
10237
+ for (const key in copy) {
10238
+ if (!Object.hasOwn(copy, key)) {
10239
+ continue;
10240
+ }
10241
+ const val = copy[key];
10242
+ const onlyShallow = shallowKeys && shallowKeys?.has(key);
10243
+ if (onlyShallow) {
10244
+ copy[key] = this.clone(val);
10245
+ }
10246
+ if (ignoreKeys && ignoreKeys.has(key)) {
10247
+ continue;
10248
+ }
10249
+ if (!onlyShallow && val !== null && typeof val === "object") {
10250
+ stack.push(val);
10251
+ stackParentKey.push(key);
10252
+ stackParent.push(copy);
10253
+ }
10135
10254
  }
10136
- copy[key] = this.safeObjectVisit(value, (obj) => recurse(obj));
10137
10255
  }
10138
10256
  }
10139
- return mapper(copy);
10140
- };
10141
- return recurse(startObject);
10257
+ handleMapper();
10258
+ }
10259
+ if (stack.length >= this.maxStackSize) {
10260
+ throw new Error("Transform object stack overflowed");
10261
+ }
10262
+ handleMapper();
10263
+ return resultWrap.res;
10142
10264
  }
10143
10265
  /**
10144
10266
  * Visitor that visits all objects. Visits deeper objects first.
10145
10267
  */
10146
10268
  visitObject(startObject, visitor, preVisitor = () => ({})) {
10269
+ const defaults2 = this.defaultContext;
10270
+ const defaultContinues = defaults2.continue ?? true;
10271
+ const defaultIgnoreKeys = defaults2.ignoreKeys;
10272
+ const defaultShortcut = defaults2.shortcut ?? false;
10147
10273
  let didShortCut = false;
10148
- const recurse = (curObject) => {
10149
- const context = preVisitor(curObject);
10150
- didShortCut = context.shortcut ?? false;
10151
- const continues = context.continue ?? true;
10152
- if (continues && !didShortCut) {
10153
- for (const value of Object.values(curObject)) {
10154
- if (didShortCut) {
10155
- return;
10274
+ const stack = [startObject];
10275
+ const handleVisitorOnLen = [];
10276
+ const visitorStack = [];
10277
+ function handleVisitor() {
10278
+ while (stack.length === handleVisitorOnLen.at(-1)) {
10279
+ handleVisitorOnLen.pop();
10280
+ const toVisit = visitorStack.pop();
10281
+ visitor(toVisit);
10282
+ }
10283
+ }
10284
+ while (stack.length > 0 && stack.length < this.maxStackSize) {
10285
+ const curObject = stack.pop();
10286
+ if (!didShortCut) {
10287
+ if (Array.isArray(curObject)) {
10288
+ for (let i = curObject.length - 1; i >= 0; i--) {
10289
+ stack.push(curObject[i]);
10290
+ }
10291
+ handleVisitor();
10292
+ continue;
10293
+ }
10294
+ const context = preVisitor(curObject);
10295
+ didShortCut = context.shortcut ?? defaultShortcut;
10296
+ const continues = context.continue ?? defaultContinues;
10297
+ const ignoreKeys = context.ignoreKeys ?? defaultIgnoreKeys;
10298
+ handleVisitorOnLen.push(stack.length);
10299
+ visitorStack.push(curObject);
10300
+ if (continues && !didShortCut) {
10301
+ for (const key in curObject) {
10302
+ if (!Object.hasOwn(curObject, key)) {
10303
+ continue;
10304
+ }
10305
+ if (ignoreKeys && ignoreKeys.has(key)) {
10306
+ continue;
10307
+ }
10308
+ const val = curObject[key];
10309
+ if (val && typeof val === "object") {
10310
+ stack.push(val);
10311
+ }
10156
10312
  }
10157
- this.safeObjectVisit(value, (obj) => recurse(obj));
10158
10313
  }
10159
10314
  }
10160
- visitor(curObject);
10161
- };
10162
- recurse(startObject);
10315
+ handleVisitor();
10316
+ }
10317
+ if (stack.length >= this.maxStackSize) {
10318
+ throw new Error("Transform object stack overflowed");
10319
+ }
10320
+ handleVisitor();
10321
+ }
10322
+ };
10323
+
10324
+ // lib/TransformerTyped.js
10325
+ var TransformerTyped = class extends TransformerObject {
10326
+ defaultNodePreVisitor;
10327
+ constructor(defaultContext = {}, defaultNodePreVisitor = {}) {
10328
+ super(defaultContext);
10329
+ this.defaultNodePreVisitor = defaultNodePreVisitor;
10163
10330
  }
10331
+ /**
10332
+ * Transform a single node.
10333
+ * The transformation calls the preVisitor from starting from the startObject.
10334
+ * The preVisitor can dictate whether transformation should be stopped.
10335
+ * Note that stopping the transformation also prevets further copying.
10336
+ * The transformer itself transforms object starting with the deepest one that can be visited.
10337
+ * The transformer callback is performed on a copy of the original.
10338
+ * @param startObject
10339
+ * @param nodeCallBacks
10340
+ */
10164
10341
  transformNode(startObject, nodeCallBacks) {
10165
- const transformWrapper = (curObject) => {
10166
- const casted = curObject;
10342
+ const transformWrapper = (copy, orig) => {
10343
+ let ogTransform;
10344
+ const casted = copy;
10167
10345
  if (casted.type) {
10168
- const ogFunc = nodeCallBacks[casted.type]?.transform;
10169
- if (ogFunc) {
10170
- return ogFunc(casted);
10171
- }
10346
+ ogTransform = nodeCallBacks[casted.type]?.transform;
10172
10347
  }
10173
- return curObject;
10348
+ return ogTransform ? ogTransform(casted, orig) : copy;
10174
10349
  };
10175
- const preTransformWrapper = (curObject) => {
10350
+ const nodeDefaults = this.defaultNodePreVisitor;
10351
+ const preVisitWrapper = (curObject) => {
10352
+ let ogPreVisit;
10353
+ let nodeContext = {};
10176
10354
  const casted = curObject;
10177
10355
  if (casted.type) {
10178
- const ogFunc = nodeCallBacks[casted.type]?.preVisitor;
10179
- if (ogFunc) {
10180
- return ogFunc(casted);
10181
- }
10356
+ ogPreVisit = nodeCallBacks[casted.type]?.preVisitor;
10357
+ nodeContext = nodeDefaults[casted.type] ?? nodeContext;
10182
10358
  }
10183
- return {};
10359
+ return ogPreVisit ? { ...nodeContext, ...ogPreVisit(casted) } : nodeContext;
10184
10360
  };
10185
- return this.transformObject(startObject, transformWrapper, preTransformWrapper);
10361
+ return this.transformObject(startObject, transformWrapper, preVisitWrapper);
10186
10362
  }
10363
+ /**
10364
+ * Similar to {@link this.transformNode}, but without copying the startObject.
10365
+ * The pre-visitor visits starting from the root, going deeper, while the actual visitor goes in reverse.
10366
+ * @param startObject
10367
+ * @param nodeCallBacks
10368
+ */
10187
10369
  visitNode(startObject, nodeCallBacks) {
10188
- const visitWrapper = (curObject) => {
10370
+ const visitorWrapper = (curObject) => {
10189
10371
  const casted = curObject;
10190
10372
  if (casted.type) {
10191
- const ogFunc = nodeCallBacks[casted.type]?.visitor;
10192
- if (ogFunc) {
10193
- ogFunc(casted);
10373
+ const ogTransform = nodeCallBacks[casted.type]?.visitor;
10374
+ if (ogTransform) {
10375
+ ogTransform(casted);
10194
10376
  }
10195
10377
  }
10196
10378
  };
10379
+ const nodeDefaults = this.defaultNodePreVisitor;
10197
10380
  const preVisitWrapper = (curObject) => {
10381
+ let ogPreVisit;
10382
+ let nodeContext = {};
10198
10383
  const casted = curObject;
10199
10384
  if (casted.type) {
10200
- const ogFunc = nodeCallBacks[casted.type]?.preVisitor;
10201
- if (ogFunc) {
10202
- return ogFunc(casted);
10203
- }
10385
+ ogPreVisit = nodeCallBacks[casted.type]?.preVisitor;
10386
+ nodeContext = nodeDefaults[casted.type] ?? nodeContext;
10204
10387
  }
10205
- return {};
10388
+ return ogPreVisit ? { ...nodeContext, ...ogPreVisit(casted) } : nodeContext;
10206
10389
  };
10207
- this.visitObject(startObject, visitWrapper, preVisitWrapper);
10390
+ return this.visitObject(startObject, visitorWrapper, preVisitWrapper);
10208
10391
  }
10392
+ /**
10393
+ * Traverses only selected nodes as returned by the function.
10394
+ * @param currentNode
10395
+ * @param traverse
10396
+ */
10209
10397
  traverseNodes(currentNode, traverse) {
10210
10398
  let didShortCut = false;
10211
10399
  const recurse = (curNode) => {
@@ -10226,11 +10414,24 @@ var TransformerType = class {
10226
10414
  recurse(currentNode);
10227
10415
  }
10228
10416
  };
10229
- var TransformerSubType = class extends TransformerType {
10417
+
10418
+ // lib/TransformerSubTyped.js
10419
+ var TransformerSubTyped = class extends TransformerTyped {
10420
+ constructor(defaultContext = {}, defaultNodePreVisitor = {}) {
10421
+ super(defaultContext, defaultNodePreVisitor);
10422
+ }
10423
+ /**
10424
+ * Shares the functionality and first two arguments with {@link this.transformNode}.
10425
+ * The third argument allows you to also transform based on the subType of objects.
10426
+ * Note that when a callback for the subtype is provided, the callback for the general type is **NOT** executed.
10427
+ * @param startObject
10428
+ * @param nodeCallBacks
10429
+ * @param nodeSpecificCallBacks
10430
+ */
10230
10431
  transformNodeSpecific(startObject, nodeCallBacks, nodeSpecificCallBacks) {
10231
- const transformWrapper = (curObject) => {
10432
+ const transformWrapper = (copy, orig) => {
10232
10433
  let ogTransform;
10233
- const casted = curObject;
10434
+ const casted = copy;
10234
10435
  if (casted.type && casted.subType) {
10235
10436
  const specific = nodeSpecificCallBacks[casted.type];
10236
10437
  if (specific) {
@@ -10240,7 +10441,7 @@ var TransformerSubType = class extends TransformerType {
10240
10441
  ogTransform = nodeCallBacks[casted.type]?.transform;
10241
10442
  }
10242
10443
  }
10243
- return ogTransform ? ogTransform(casted) : curObject;
10444
+ return ogTransform ? ogTransform(casted, orig) : copy;
10244
10445
  };
10245
10446
  const preVisitWrapper = (curObject) => {
10246
10447
  let ogPreVisit;
@@ -10254,12 +10455,13 @@ var TransformerSubType = class extends TransformerType {
10254
10455
  ogPreVisit = nodeCallBacks[casted.type]?.preVisitor;
10255
10456
  }
10256
10457
  }
10257
- return ogPreVisit ? ogPreVisit(casted) : curObject;
10458
+ return ogPreVisit ? ogPreVisit(casted) : {};
10258
10459
  };
10259
10460
  return this.transformObject(startObject, transformWrapper, preVisitWrapper);
10260
10461
  }
10261
10462
  /**
10262
- * When both nodeCallBack and NodeSpecific callBack are matched, will only look at nodeSpecifCallback
10463
+ * Similar to {@link this.visitNode} but also allows you to match based on the subtype of objects.
10464
+ * When both nodeCallBack and NodeSpecific callBack are matched, will only visit nodeSpecifCallback
10263
10465
  */
10264
10466
  visitNodeSpecific(startObject, nodeCallBacks, nodeSpecificCallBacks) {
10265
10467
  const visitWrapper = (curObject) => {
@@ -10290,10 +10492,16 @@ var TransformerSubType = class extends TransformerType {
10290
10492
  ogPreVisit = nodeCallBacks[casted.type]?.preVisitor;
10291
10493
  }
10292
10494
  }
10293
- return ogPreVisit ? ogPreVisit(casted) : curObject;
10495
+ return ogPreVisit ? ogPreVisit(casted) : {};
10294
10496
  };
10295
10497
  this.visitObject(startObject, visitWrapper, preVisitWrapper);
10296
10498
  }
10499
+ /**
10500
+ * Similar to {@link this.traverseNodes} but also allows you to match based on the subtype of objects.
10501
+ * @param currentNode
10502
+ * @param traverseNode
10503
+ * @param traverseSubNode
10504
+ */
10297
10505
  traverseSubNodes(currentNode, traverseNode, traverseSubNode) {
10298
10506
  let didShortCut = false;
10299
10507
  const recurse = (curNode) => {