@skeptools/skep-organization-project 0.0.16 → 0.0.17

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 (48) hide show
  1. package/.jsii +28 -3
  2. package/API.md +63 -1
  3. package/lib/skep-organization-project.js +1 -1
  4. package/node_modules/liquidjs/README.md +15 -10
  5. package/node_modules/liquidjs/dist/context/context.d.ts +6 -3
  6. package/node_modules/liquidjs/dist/drop/blank-drop.d.ts +1 -0
  7. package/node_modules/liquidjs/dist/drop/empty-drop.d.ts +1 -0
  8. package/node_modules/liquidjs/dist/index.d.ts +2 -2
  9. package/node_modules/liquidjs/dist/liquid-options.d.ts +2 -0
  10. package/node_modules/liquidjs/dist/liquid.browser.min.js +1 -1
  11. package/node_modules/liquidjs/dist/liquid.browser.min.js.map +1 -1
  12. package/node_modules/liquidjs/dist/liquid.browser.mjs +712 -45
  13. package/node_modules/liquidjs/dist/liquid.browser.umd.js +1573 -215
  14. package/node_modules/liquidjs/dist/liquid.browser.umd.js.map +1 -1
  15. package/node_modules/liquidjs/dist/liquid.d.ts +29 -1
  16. package/node_modules/liquidjs/dist/liquid.node.js +699 -45
  17. package/node_modules/liquidjs/dist/liquid.node.mjs +712 -45
  18. package/node_modules/liquidjs/dist/render/expression.d.ts +1 -1
  19. package/node_modules/liquidjs/dist/render/operator.d.ts +1 -0
  20. package/node_modules/liquidjs/dist/tags/assign.d.ts +5 -0
  21. package/node_modules/liquidjs/dist/tags/block.d.ts +2 -0
  22. package/node_modules/liquidjs/dist/tags/break.d.ts +1 -1
  23. package/node_modules/liquidjs/dist/tags/capture.d.ts +5 -1
  24. package/node_modules/liquidjs/dist/tags/case.d.ts +3 -0
  25. package/node_modules/liquidjs/dist/tags/continue.d.ts +1 -1
  26. package/node_modules/liquidjs/dist/tags/cycle.d.ts +2 -0
  27. package/node_modules/liquidjs/dist/tags/decrement.d.ts +3 -0
  28. package/node_modules/liquidjs/dist/tags/echo.d.ts +2 -0
  29. package/node_modules/liquidjs/dist/tags/for.d.ts +4 -0
  30. package/node_modules/liquidjs/dist/tags/if.d.ts +3 -0
  31. package/node_modules/liquidjs/dist/tags/include.d.ts +5 -1
  32. package/node_modules/liquidjs/dist/tags/increment.d.ts +3 -0
  33. package/node_modules/liquidjs/dist/tags/layout.d.ts +4 -0
  34. package/node_modules/liquidjs/dist/tags/liquid.d.ts +1 -0
  35. package/node_modules/liquidjs/dist/tags/render.d.ts +4 -0
  36. package/node_modules/liquidjs/dist/tags/tablerow.d.ts +4 -0
  37. package/node_modules/liquidjs/dist/tags/unless.d.ts +3 -0
  38. package/node_modules/liquidjs/dist/template/analysis.d.ts +85 -0
  39. package/node_modules/liquidjs/dist/template/analysis.spec.d.ts +1 -0
  40. package/node_modules/liquidjs/dist/template/hash.d.ts +2 -1
  41. package/node_modules/liquidjs/dist/template/index.d.ts +1 -0
  42. package/node_modules/liquidjs/dist/template/output.d.ts +2 -1
  43. package/node_modules/liquidjs/dist/template/template.d.ts +29 -0
  44. package/node_modules/liquidjs/dist/tokens/liquid-tag-token.d.ts +1 -1
  45. package/node_modules/liquidjs/dist/util/type-guards.d.ts +2 -1
  46. package/node_modules/liquidjs/dist/util/underscore.d.ts +3 -0
  47. package/node_modules/liquidjs/package.json +2 -1
  48. package/package.json +2 -2
@@ -1,6 +1,6 @@
1
1
  /*
2
- * liquidjs@10.18.0, https://github.com/harttle/liquidjs
3
- * (c) 2016-2024 harttle
2
+ * liquidjs@10.20.1, https://github.com/harttle/liquidjs
3
+ * (c) 2016-2025 harttle
4
4
  * Released under the MIT License.
5
5
  */
6
6
  import { PassThrough } from 'stream';
@@ -125,6 +125,9 @@ function isArray(value) {
125
125
  // be compatible with IE 8
126
126
  return toString$1.call(value) === '[object Array]';
127
127
  }
128
+ function isArrayLike(value) {
129
+ return value && isNumber(value.length);
130
+ }
128
131
  function isIterable(value) {
129
132
  return isObject(value) && Symbol.iterator in value;
130
133
  }
@@ -210,6 +213,17 @@ function argumentsToValue(fn) {
210
213
  }
211
214
  function escapeRegExp(text) {
212
215
  return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
216
+ }
217
+ /** Return an array containing unique elements from _array_. Works with nested arrays and objects. */
218
+ function* strictUniq(array) {
219
+ const seen = new Set();
220
+ for (const element of array) {
221
+ const key = JSON.stringify(element);
222
+ if (!seen.has(key)) {
223
+ seen.add(key);
224
+ yield element;
225
+ }
226
+ }
213
227
  }
214
228
 
215
229
  /**
@@ -410,6 +424,9 @@ class EmptyDrop extends Drop {
410
424
  valueOf() {
411
425
  return '';
412
426
  }
427
+ static is(value) {
428
+ return value instanceof EmptyDrop;
429
+ }
413
430
  }
414
431
 
415
432
  class BlankDrop extends EmptyDrop {
@@ -422,6 +439,9 @@ class BlankDrop extends EmptyDrop {
422
439
  return /^\s*$/.test(value);
423
440
  return super.equals(value);
424
441
  }
442
+ static is(value) {
443
+ return value instanceof BlankDrop;
444
+ }
425
445
  }
426
446
 
427
447
  class ForloopDrop extends Drop {
@@ -746,7 +766,11 @@ function getDateTimeFormat() {
746
766
 
747
767
  // one minute in milliseconds
748
768
  const OneMinute = 60000;
749
- const ISO8601_TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):(\d{2}))$/;
769
+ /**
770
+ * Need support both ISO8601 and RFC2822 as in major browsers & NodeJS
771
+ * RFC2822: https://datatracker.ietf.org/doc/html/rfc2822#section-3.3
772
+ */
773
+ const TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):?(\d{2}))$/;
750
774
  const monthNames = [
751
775
  'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
752
776
  'September', 'October', 'November', 'December'
@@ -863,7 +887,7 @@ class LiquidDate {
863
887
  * Given that a template is expected to be parsed fewer times than rendered.
864
888
  */
865
889
  static createDateFixedToTimezone(dateString, locale) {
866
- const m = dateString.match(ISO8601_TIMEZONE_PATTERN);
890
+ const m = dateString.match(TIMEZONE_PATTERN);
867
891
  // representing a UTC timestamp
868
892
  if (m && m[1] === 'Z') {
869
893
  return new LiquidDate(+new Date(dateString), locale, 0);
@@ -1149,7 +1173,9 @@ class LiquidTagToken extends DelimitedToken {
1149
1173
  this.name = this.tokenizer.readTagName();
1150
1174
  this.tokenizer.assert(this.name, 'illegal liquid tag syntax');
1151
1175
  this.tokenizer.skipBlank();
1152
- this.args = this.tokenizer.remaining();
1176
+ }
1177
+ get args() {
1178
+ return this.tokenizer.input.slice(this.tokenizer.p, this.contentRange[1]);
1153
1179
  }
1154
1180
  }
1155
1181
 
@@ -1242,7 +1268,7 @@ class Render {
1242
1268
  const html = yield tpl.render(ctx, emitter);
1243
1269
  // if not, it'll return an `html`, write to the emitter for it
1244
1270
  html && emitter.write(html);
1245
- if (emitter['break'] || emitter['continue'])
1271
+ if (ctx.breakCalled || ctx.continueCalled)
1246
1272
  break;
1247
1273
  }
1248
1274
  catch (e) {
@@ -1326,6 +1352,7 @@ function evalQuotedToken(token) {
1326
1352
  function* evalRangeToken(token, ctx) {
1327
1353
  const low = yield evalToken(token.lhs, ctx);
1328
1354
  const high = yield evalToken(token.rhs, ctx);
1355
+ ctx.memoryLimit.use(high - low + 1);
1329
1356
  return range(+low, +high + 1);
1330
1357
  }
1331
1358
  function* toPostfix(tokens) {
@@ -1417,6 +1444,9 @@ function arrayEquals(lhs, rhs) {
1417
1444
  if (lhs.length !== rhs.length)
1418
1445
  return false;
1419
1446
  return !lhs.some((value, i) => !equals(value, rhs[i]));
1447
+ }
1448
+ function arrayIncludes(arr, item) {
1449
+ return arr.some(value => equals(value, item));
1420
1450
  }
1421
1451
 
1422
1452
  class Node {
@@ -2313,9 +2343,9 @@ class Tag extends TemplateImpl {
2313
2343
  * hash['reversed'] === undefined
2314
2344
  */
2315
2345
  class Hash {
2316
- constructor(markup, jekyllStyle) {
2346
+ constructor(input, jekyllStyle) {
2317
2347
  this.hash = {};
2318
- const tokenizer = new Tokenizer(markup, {});
2348
+ const tokenizer = input instanceof Tokenizer ? input : new Tokenizer(input, {});
2319
2349
  for (const hash of tokenizer.readHashes(jekyllStyle)) {
2320
2350
  this.hash[hash.name.content] = hash.value;
2321
2351
  }
@@ -2415,6 +2445,9 @@ class Output extends TemplateImpl {
2415
2445
  const val = yield this.value.value(ctx, false);
2416
2446
  emitter.write(val);
2417
2447
  }
2448
+ *arguments() {
2449
+ yield this.value;
2450
+ }
2418
2451
  }
2419
2452
 
2420
2453
  class HTML extends TemplateImpl {
@@ -2427,6 +2460,336 @@ class HTML extends TemplateImpl {
2427
2460
  }
2428
2461
  }
2429
2462
 
2463
+ /**
2464
+ * A variable's segments and location, which can be coerced to a string.
2465
+ */
2466
+ class Variable {
2467
+ constructor(segments, location) {
2468
+ this.segments = segments;
2469
+ this.location = location;
2470
+ }
2471
+ toString() {
2472
+ return segmentsString(this.segments, true);
2473
+ }
2474
+ /** Return this variable's segments as an array, possibly with nested arrays for nested paths. */
2475
+ toArray() {
2476
+ function* _visit(...segments) {
2477
+ for (const segment of segments) {
2478
+ if (segment instanceof Variable) {
2479
+ yield Array.from(_visit(...segment.segments));
2480
+ }
2481
+ else {
2482
+ yield segment;
2483
+ }
2484
+ }
2485
+ }
2486
+ return Array.from(_visit(...this.segments));
2487
+ }
2488
+ }
2489
+ /**
2490
+ * Group variables by the string representation of their root segment.
2491
+ */
2492
+ class VariableMap {
2493
+ constructor() {
2494
+ this.map = new Map();
2495
+ }
2496
+ get(key) {
2497
+ const k = segmentsString([key.segments[0]]);
2498
+ if (!this.map.has(k)) {
2499
+ this.map.set(k, []);
2500
+ }
2501
+ return this.map.get(k);
2502
+ }
2503
+ has(key) {
2504
+ return this.map.has(segmentsString([key.segments[0]]));
2505
+ }
2506
+ push(variable) {
2507
+ this.get(variable).push(variable);
2508
+ }
2509
+ asObject() {
2510
+ return Object.fromEntries(this.map);
2511
+ }
2512
+ }
2513
+ const defaultStaticAnalysisOptions = {
2514
+ partials: true
2515
+ };
2516
+ function* _analyze(templates, partials, sync) {
2517
+ const variables = new VariableMap();
2518
+ const globals = new VariableMap();
2519
+ const locals = new VariableMap();
2520
+ const rootScope = new DummyScope(new Set());
2521
+ // Names of partial templates that we've already analyzed.
2522
+ const seen = new Set();
2523
+ function updateVariables(variable, scope) {
2524
+ variables.push(variable);
2525
+ const aliased = scope.alias(variable);
2526
+ if (aliased !== undefined) {
2527
+ const root = aliased.segments[0];
2528
+ // TODO: What if a a template renders a rendered template? Do we need scope.parent?
2529
+ if (isString(root) && !rootScope.has(root)) {
2530
+ globals.push(aliased);
2531
+ }
2532
+ }
2533
+ else {
2534
+ const root = variable.segments[0];
2535
+ if (isString(root) && !scope.has(root)) {
2536
+ globals.push(variable);
2537
+ }
2538
+ }
2539
+ // Recurse for nested Variables
2540
+ for (const segment of variable.segments) {
2541
+ if (segment instanceof Variable) {
2542
+ updateVariables(segment, scope);
2543
+ }
2544
+ }
2545
+ }
2546
+ function* visit(template, scope) {
2547
+ if (template.arguments) {
2548
+ for (const arg of template.arguments()) {
2549
+ for (const variable of extractVariables(arg)) {
2550
+ updateVariables(variable, scope);
2551
+ }
2552
+ }
2553
+ }
2554
+ if (template.localScope) {
2555
+ for (const ident of template.localScope()) {
2556
+ scope.add(ident.content);
2557
+ scope.deleteAlias(ident.content);
2558
+ const [row, col] = ident.getPosition();
2559
+ locals.push(new Variable([ident.content], { row, col, file: ident.file }));
2560
+ }
2561
+ }
2562
+ if (template.children) {
2563
+ if (template.partialScope) {
2564
+ const partial = template.partialScope();
2565
+ if (partial === undefined) {
2566
+ // Layouts, for example, can have children that are not partials.
2567
+ for (const child of (yield template.children(partials, sync))) {
2568
+ yield visit(child, scope);
2569
+ }
2570
+ return;
2571
+ }
2572
+ if (seen.has(partial.name))
2573
+ return;
2574
+ const partialScopeNames = new Set();
2575
+ const partialScope = partial.isolated
2576
+ ? new DummyScope(partialScopeNames)
2577
+ : scope.push(partialScopeNames);
2578
+ for (const name of partial.scope) {
2579
+ if (isString(name)) {
2580
+ partialScopeNames.add(name);
2581
+ }
2582
+ else {
2583
+ const [alias, argument] = name;
2584
+ partialScopeNames.add(alias);
2585
+ const variables = Array.from(extractVariables(argument));
2586
+ if (variables.length) {
2587
+ partialScope.setAlias(alias, variables[0].segments);
2588
+ }
2589
+ }
2590
+ }
2591
+ for (const child of (yield template.children(partials, sync))) {
2592
+ yield visit(child, partialScope);
2593
+ seen.add(partial.name);
2594
+ }
2595
+ partialScope.pop();
2596
+ }
2597
+ else {
2598
+ if (template.blockScope) {
2599
+ scope.push(new Set(template.blockScope()));
2600
+ }
2601
+ for (const child of (yield template.children(partials, sync))) {
2602
+ yield visit(child, scope);
2603
+ }
2604
+ if (template.blockScope) {
2605
+ scope.pop();
2606
+ }
2607
+ }
2608
+ }
2609
+ }
2610
+ for (const template of templates) {
2611
+ yield visit(template, rootScope);
2612
+ }
2613
+ return {
2614
+ variables: variables.asObject(),
2615
+ globals: globals.asObject(),
2616
+ locals: locals.asObject()
2617
+ };
2618
+ }
2619
+ /**
2620
+ * Statically analyze a template and report variable usage.
2621
+ */
2622
+ function analyze(template, options = {}) {
2623
+ const opts = Object.assign(Object.assign({}, defaultStaticAnalysisOptions), options);
2624
+ return toPromise(_analyze(template, opts.partials, false));
2625
+ }
2626
+ /**
2627
+ * Statically analyze a template and report variable usage.
2628
+ */
2629
+ function analyzeSync(template, options = {}) {
2630
+ const opts = Object.assign(Object.assign({}, defaultStaticAnalysisOptions), options);
2631
+ return toValueSync(_analyze(template, opts.partials, true));
2632
+ }
2633
+ /**
2634
+ * A stack to manage scopes while traversing templates during static analysis.
2635
+ */
2636
+ class DummyScope {
2637
+ constructor(globals) {
2638
+ this.stack = [{ names: globals, aliases: new Map() }];
2639
+ }
2640
+ /** Return true if `name` is in scope. */
2641
+ has(name) {
2642
+ for (const scope of this.stack) {
2643
+ if (scope.names.has(name)) {
2644
+ return true;
2645
+ }
2646
+ }
2647
+ return false;
2648
+ }
2649
+ push(scope) {
2650
+ this.stack.push({ names: scope, aliases: new Map() });
2651
+ return this;
2652
+ }
2653
+ pop() {
2654
+ var _a;
2655
+ return (_a = this.stack.pop()) === null || _a === void 0 ? void 0 : _a.names;
2656
+ }
2657
+ // Add a name to the template scope.
2658
+ add(name) {
2659
+ this.stack[0].names.add(name);
2660
+ }
2661
+ /** Return the variable that `variable` aliases, or `variable` if it doesn't alias anything. */
2662
+ alias(variable) {
2663
+ const root = variable.segments[0];
2664
+ if (!isString(root))
2665
+ return undefined;
2666
+ const alias = this.getAlias(root);
2667
+ if (alias === undefined)
2668
+ return undefined;
2669
+ return new Variable([...alias, ...variable.segments.slice(1)], variable.location);
2670
+ }
2671
+ // TODO: `from` could be a path with multiple segments, like `include.x`.
2672
+ setAlias(from, to) {
2673
+ this.stack[this.stack.length - 1].aliases.set(from, to);
2674
+ }
2675
+ deleteAlias(name) {
2676
+ this.stack[this.stack.length - 1].aliases.delete(name);
2677
+ }
2678
+ getAlias(name) {
2679
+ for (const scope of this.stack) {
2680
+ if (scope.aliases.has(name)) {
2681
+ return scope.aliases.get(name);
2682
+ }
2683
+ // If a scope has defined `name`, then it masks aliases in parent scopes.
2684
+ if (scope.names.has(name)) {
2685
+ return undefined;
2686
+ }
2687
+ }
2688
+ return undefined;
2689
+ }
2690
+ }
2691
+ function* extractVariables(value) {
2692
+ if (isValueToken(value)) {
2693
+ yield* extractValueTokenVariables(value);
2694
+ }
2695
+ else if (value instanceof Value) {
2696
+ yield* extractFilteredValueVariables(value);
2697
+ }
2698
+ }
2699
+ function* extractFilteredValueVariables(value) {
2700
+ for (const token of value.initial.postfix) {
2701
+ if (isValueToken(token)) {
2702
+ yield* extractValueTokenVariables(token);
2703
+ }
2704
+ }
2705
+ for (const filter of value.filters) {
2706
+ for (const arg of filter.args) {
2707
+ if (isKeyValuePair(arg) && arg[1]) {
2708
+ yield* extractValueTokenVariables(arg[1]);
2709
+ }
2710
+ else if (isValueToken(arg)) {
2711
+ yield* extractValueTokenVariables(arg);
2712
+ }
2713
+ }
2714
+ }
2715
+ }
2716
+ function* extractValueTokenVariables(token) {
2717
+ if (isRangeToken(token)) {
2718
+ yield* extractValueTokenVariables(token.lhs);
2719
+ yield* extractValueTokenVariables(token.rhs);
2720
+ }
2721
+ else if (isPropertyAccessToken(token)) {
2722
+ yield extractPropertyAccessVariable(token);
2723
+ }
2724
+ }
2725
+ function extractPropertyAccessVariable(token) {
2726
+ const segments = [];
2727
+ // token is not guaranteed to have `file` set. We'll try to get it from a prop if not.
2728
+ let file = token.file;
2729
+ // Here we're flattening the first segment of a path if it is a nested path.
2730
+ const root = token.props[0];
2731
+ file = file || root.file;
2732
+ if (isQuotedToken(root) || isNumberToken(root) || isWordToken(root)) {
2733
+ segments.push(root.content);
2734
+ }
2735
+ else if (isPropertyAccessToken(root)) {
2736
+ // Flatten paths that start with a nested path.
2737
+ segments.push(...extractPropertyAccessVariable(root).segments);
2738
+ }
2739
+ for (const prop of token.props.slice(1)) {
2740
+ file = file || prop.file;
2741
+ if (isQuotedToken(prop) || isNumberToken(prop) || isWordToken(prop)) {
2742
+ segments.push(prop.content);
2743
+ }
2744
+ else if (isPropertyAccessToken(prop)) {
2745
+ segments.push(extractPropertyAccessVariable(prop));
2746
+ }
2747
+ }
2748
+ const [row, col] = token.getPosition();
2749
+ return new Variable(segments, {
2750
+ row,
2751
+ col,
2752
+ file
2753
+ });
2754
+ }
2755
+ // This is used to detect segments that can be represented with dot notation
2756
+ // when creating a string representation of VariableSegments.
2757
+ const RE_PROPERTY = /^[\u0080-\uFFFFa-zA-Z_][\u0080-\uFFFFa-zA-Z0-9_-]*$/;
2758
+ /**
2759
+ * Return a string representation of segments using dot notation where possible.
2760
+ * @param segments - The property names and array indices that make up a path to a variable.
2761
+ * @param bracketedRoot - If false (the default), don't surround the root segment with square brackets.
2762
+ */
2763
+ function segmentsString(segments, bracketedRoot = false) {
2764
+ const buf = [];
2765
+ const root = segments[0];
2766
+ if (isString(root)) {
2767
+ if (!bracketedRoot || root.match(RE_PROPERTY)) {
2768
+ buf.push(`${root}`);
2769
+ }
2770
+ else {
2771
+ buf.push(`['${root}']`);
2772
+ }
2773
+ }
2774
+ for (const segment of segments.slice(1)) {
2775
+ if (segment instanceof Variable) {
2776
+ buf.push(`[${segmentsString(segment.segments)}]`);
2777
+ }
2778
+ else if (isString(segment)) {
2779
+ if (segment.match(RE_PROPERTY)) {
2780
+ buf.push(`.${segment}`);
2781
+ }
2782
+ else {
2783
+ buf.push(`['${segment}']`);
2784
+ }
2785
+ }
2786
+ else {
2787
+ buf.push(`[${segment}]`);
2788
+ }
2789
+ }
2790
+ return buf.join('');
2791
+ }
2792
+
2430
2793
  var LookupType;
2431
2794
  (function (LookupType) {
2432
2795
  LookupType["Partials"] = "partials";
@@ -2626,6 +2989,10 @@ function isWordToken(val) {
2626
2989
  function isRangeToken(val) {
2627
2990
  return getKind(val) === TokenKind.Range;
2628
2991
  }
2992
+ function isValueToken(val) {
2993
+ // valueTokenBitMask = TokenKind.Number | TokenKind.Literal | TokenKind.Quoted | TokenKind.PropertyAccess | TokenKind.Range
2994
+ return (getKind(val) & 1667) > 0;
2995
+ }
2629
2996
  function getKind(val) {
2630
2997
  return val ? val.kind : -1;
2631
2998
  }
@@ -2642,7 +3009,8 @@ var typeGuards = /*#__PURE__*/Object.freeze({
2642
3009
  isNumberToken: isNumberToken,
2643
3010
  isPropertyAccessToken: isPropertyAccessToken,
2644
3011
  isWordToken: isWordToken,
2645
- isRangeToken: isRangeToken
3012
+ isRangeToken: isRangeToken,
3013
+ isValueToken: isValueToken
2646
3014
  });
2647
3015
 
2648
3016
  class Context {
@@ -2654,6 +3022,8 @@ class Context {
2654
3022
  */
2655
3023
  this.scopes = [{}];
2656
3024
  this.registers = {};
3025
+ this.breakCalled = false;
3026
+ this.continueCalled = false;
2657
3027
  this.sync = !!renderOptions.sync;
2658
3028
  this.opts = opts;
2659
3029
  this.globals = (_a = renderOptions.globals) !== null && _a !== void 0 ? _a : opts.globals;
@@ -2689,7 +3059,7 @@ class Context {
2689
3059
  return toValueSync(this._get(paths));
2690
3060
  }
2691
3061
  *_get(paths) {
2692
- const scope = this.findScope(paths[0]);
3062
+ const scope = this.findScope(paths[0]); // first prop should always be a string
2693
3063
  return yield this._getFromScope(scope, paths);
2694
3064
  }
2695
3065
  /**
@@ -2741,6 +3111,7 @@ class Context {
2741
3111
  }
2742
3112
  function readProperty(obj, key, ownPropertyOnly) {
2743
3113
  obj = toLiquid(obj);
3114
+ key = toValue(key);
2744
3115
  if (isNil(obj))
2745
3116
  return obj;
2746
3117
  if (isArray(obj) && key < 0)
@@ -2888,8 +3259,8 @@ const join = argumentsToValue(function (v, arg) {
2888
3259
  this.context.memoryLimit.use(complexity);
2889
3260
  return array.join(sep);
2890
3261
  });
2891
- const last$1 = argumentsToValue((v) => isArray(v) ? last(v) : '');
2892
- const first = argumentsToValue((v) => isArray(v) ? v[0] : '');
3262
+ const last$1 = argumentsToValue((v) => isArrayLike(v) ? last(v) : '');
3263
+ const first = argumentsToValue((v) => isArrayLike(v) ? v[0] : '');
2893
3264
  const reverse = argumentsToValue(function (v) {
2894
3265
  const array = toArray(v);
2895
3266
  this.context.memoryLimit.use(array.length);
@@ -2990,10 +3361,13 @@ function* where(arr, property, expected) {
2990
3361
  for (const item of arr) {
2991
3362
  values.push(yield evalToken(token, this.context.spawn(item)));
2992
3363
  }
3364
+ const matcher = this.context.opts.jekyllWhere
3365
+ ? (v) => EmptyDrop.is(expected) ? equals(v, expected) : (isArray(v) ? arrayIncludes(v, expected) : equals(v, expected))
3366
+ : (v) => equals(v, expected);
2993
3367
  return arr.filter((_, i) => {
2994
3368
  if (expected === undefined)
2995
3369
  return isTruthy(values[i], this.context);
2996
- return equals(values[i], expected);
3370
+ return matcher(values[i]);
2997
3371
  });
2998
3372
  }
2999
3373
  function* where_exp(arr, itemName, exp) {
@@ -3010,7 +3384,7 @@ function* where_exp(arr, itemName, exp) {
3010
3384
  }
3011
3385
  function* group_by(arr, property) {
3012
3386
  const map = new Map();
3013
- arr = toArray(arr);
3387
+ arr = toEnumerable(arr);
3014
3388
  const token = new Tokenizer(stringify(property)).readScopeValue();
3015
3389
  this.context.memoryLimit.use(arr.length);
3016
3390
  for (const item of arr) {
@@ -3024,7 +3398,7 @@ function* group_by(arr, property) {
3024
3398
  function* group_by_exp(arr, itemName, exp) {
3025
3399
  const map = new Map();
3026
3400
  const keyTemplate = new Value(stringify(exp), this.liquid);
3027
- arr = toArray(arr);
3401
+ arr = toEnumerable(arr);
3028
3402
  this.context.memoryLimit.use(arr.length);
3029
3403
  for (const item of arr) {
3030
3404
  const key = yield keyTemplate.value(this.context.spawn({ [itemName]: item }));
@@ -3377,7 +3751,8 @@ const filters = Object.assign(Object.assign(Object.assign(Object.assign(Object.a
3377
3751
  class AssignTag extends Tag {
3378
3752
  constructor(token, remainTokens, liquid) {
3379
3753
  super(token, remainTokens, liquid);
3380
- this.key = this.tokenizer.readIdentifier().content;
3754
+ this.identifier = this.tokenizer.readIdentifier();
3755
+ this.key = this.identifier.content;
3381
3756
  this.tokenizer.assert(this.key, 'expected variable name');
3382
3757
  this.tokenizer.skipBlank();
3383
3758
  this.tokenizer.assert(this.tokenizer.peek() === '=', 'expected "="');
@@ -3387,6 +3762,12 @@ class AssignTag extends Tag {
3387
3762
  *render(ctx) {
3388
3763
  ctx.bottom()[this.key] = yield this.value.value(ctx, this.liquid.options.lenientIf);
3389
3764
  }
3765
+ *arguments() {
3766
+ yield this.value;
3767
+ }
3768
+ *localScope() {
3769
+ yield this.identifier;
3770
+ }
3390
3771
  }
3391
3772
 
3392
3773
  const MODIFIERS = ['offset', 'limit', 'reversed'];
@@ -3401,7 +3782,7 @@ class ForTag extends Tag {
3401
3782
  }
3402
3783
  this.variable = variable.content;
3403
3784
  this.collection = collection;
3404
- this.hash = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
3785
+ this.hash = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
3405
3786
  this.templates = [];
3406
3787
  this.elseTemplates = [];
3407
3788
  let p;
@@ -3439,16 +3820,33 @@ class ForTag extends Tag {
3439
3820
  ctx.push(scope);
3440
3821
  for (const item of collection) {
3441
3822
  scope[this.variable] = item;
3823
+ ctx.continueCalled = ctx.breakCalled = false;
3442
3824
  yield r.renderTemplates(this.templates, ctx, emitter);
3443
- if (emitter['break']) {
3444
- emitter['break'] = false;
3825
+ if (ctx.breakCalled)
3445
3826
  break;
3446
- }
3447
- emitter['continue'] = false;
3448
3827
  scope.forloop.next();
3449
3828
  }
3829
+ ctx.continueCalled = ctx.breakCalled = false;
3450
3830
  ctx.pop();
3451
3831
  }
3832
+ *children() {
3833
+ const templates = this.templates.slice();
3834
+ if (this.elseTemplates) {
3835
+ templates.push(...this.elseTemplates);
3836
+ }
3837
+ return templates;
3838
+ }
3839
+ *arguments() {
3840
+ yield this.collection;
3841
+ for (const v of Object.values(this.hash.hash)) {
3842
+ if (isValueToken(v)) {
3843
+ yield v;
3844
+ }
3845
+ }
3846
+ }
3847
+ blockScope() {
3848
+ return [this.variable, 'forloop'];
3849
+ }
3452
3850
  }
3453
3851
  function reversed(arr) {
3454
3852
  return [...arr].reverse();
@@ -3464,7 +3862,8 @@ class CaptureTag extends Tag {
3464
3862
  constructor(tagToken, remainTokens, liquid, parser) {
3465
3863
  super(tagToken, remainTokens, liquid);
3466
3864
  this.templates = [];
3467
- this.variable = this.readVariableName();
3865
+ this.identifier = this.readVariable();
3866
+ this.variable = this.identifier.content;
3468
3867
  while (remainTokens.length) {
3469
3868
  const token = remainTokens.shift();
3470
3869
  if (isTagToken(token) && token.name === 'endcapture')
@@ -3473,19 +3872,25 @@ class CaptureTag extends Tag {
3473
3872
  }
3474
3873
  throw new Error(`tag ${tagToken.getText()} not closed`);
3475
3874
  }
3875
+ readVariable() {
3876
+ let ident = this.tokenizer.readIdentifier();
3877
+ if (ident.content)
3878
+ return ident;
3879
+ ident = this.tokenizer.readQuoted();
3880
+ if (ident)
3881
+ return ident;
3882
+ throw this.tokenizer.error('invalid capture name');
3883
+ }
3476
3884
  *render(ctx) {
3477
3885
  const r = this.liquid.renderer;
3478
3886
  const html = yield r.renderTemplates(this.templates, ctx);
3479
3887
  ctx.bottom()[this.variable] = html;
3480
3888
  }
3481
- readVariableName() {
3482
- const word = this.tokenizer.readIdentifier().content;
3483
- if (word)
3484
- return word;
3485
- const quoted = this.tokenizer.readQuoted();
3486
- if (quoted)
3487
- return evalQuotedToken(quoted);
3488
- throw this.tokenizer.error('invalid capture name');
3889
+ *children() {
3890
+ return this.templates;
3891
+ }
3892
+ *localScope() {
3893
+ yield this.identifier;
3489
3894
  }
3490
3895
  }
3491
3896
 
@@ -3553,6 +3958,17 @@ class CaseTag extends Tag {
3553
3958
  yield r.renderTemplates(this.elseTemplates, ctx, emitter);
3554
3959
  }
3555
3960
  }
3961
+ *arguments() {
3962
+ yield this.value;
3963
+ yield* this.branches.flatMap(b => b.values);
3964
+ }
3965
+ *children() {
3966
+ const templates = this.branches.flatMap(b => b.templates);
3967
+ if (this.elseTemplates) {
3968
+ templates.push(...this.elseTemplates);
3969
+ }
3970
+ return templates;
3971
+ }
3556
3972
  }
3557
3973
 
3558
3974
  class CommentTag extends Tag {
@@ -3606,7 +4022,7 @@ class RenderTag extends Tag {
3606
4022
  tokenizer.p = begin;
3607
4023
  break;
3608
4024
  }
3609
- this.hash = new Hash(tokenizer.remaining(), liquid.options.keyValueSeparator);
4025
+ this.hash = new Hash(tokenizer, liquid.options.keyValueSeparator);
3610
4026
  }
3611
4027
  *render(ctx, emitter) {
3612
4028
  const { liquid, hash } = this;
@@ -3635,6 +4051,55 @@ class RenderTag extends Tag {
3635
4051
  yield liquid.renderer.renderTemplates(templates, childCtx, emitter);
3636
4052
  }
3637
4053
  }
4054
+ *children(partials, sync) {
4055
+ if (partials && isString(this['file'])) {
4056
+ return (yield this.liquid._parsePartialFile(this['file'], sync, this['currentFile']));
4057
+ }
4058
+ return [];
4059
+ }
4060
+ partialScope() {
4061
+ if (isString(this['file'])) {
4062
+ const names = Object.keys(this.hash.hash);
4063
+ if (this['with']) {
4064
+ const { value, alias } = this['with'];
4065
+ if (isString(alias)) {
4066
+ names.push([alias, value]);
4067
+ }
4068
+ else if (isString(this.file)) {
4069
+ names.push([this.file, value]);
4070
+ }
4071
+ }
4072
+ if (this['for']) {
4073
+ const { value, alias } = this['for'];
4074
+ if (isString(alias)) {
4075
+ names.push([alias, value]);
4076
+ }
4077
+ else if (isString(this.file)) {
4078
+ names.push([this.file, value]);
4079
+ }
4080
+ }
4081
+ return { name: this['file'], isolated: true, scope: names };
4082
+ }
4083
+ }
4084
+ *arguments() {
4085
+ for (const v of Object.values(this.hash.hash)) {
4086
+ if (isValueToken(v)) {
4087
+ yield v;
4088
+ }
4089
+ }
4090
+ if (this['with']) {
4091
+ const { value } = this['with'];
4092
+ if (isValueToken(value)) {
4093
+ yield value;
4094
+ }
4095
+ }
4096
+ if (this['for']) {
4097
+ const { value } = this['for'];
4098
+ if (isValueToken(value)) {
4099
+ yield value;
4100
+ }
4101
+ }
4102
+ }
3638
4103
  }
3639
4104
  /**
3640
4105
  * @return null for "none",
@@ -3691,7 +4156,7 @@ class IncludeTag extends Tag {
3691
4156
  }
3692
4157
  else
3693
4158
  tokenizer.p = begin;
3694
- this.hash = new Hash(tokenizer.remaining(), liquid.options.jekyllInclude || liquid.options.keyValueSeparator);
4159
+ this.hash = new Hash(tokenizer, liquid.options.jekyllInclude || liquid.options.keyValueSeparator);
3695
4160
  }
3696
4161
  *render(ctx, emitter) {
3697
4162
  const { liquid, hash, withVar } = this;
@@ -3710,12 +4175,43 @@ class IncludeTag extends Tag {
3710
4175
  ctx.pop();
3711
4176
  ctx.restoreRegister(saved);
3712
4177
  }
4178
+ *children(partials, sync) {
4179
+ if (partials && isString(this['file'])) {
4180
+ return (yield this.liquid._parsePartialFile(this['file'], sync, this['currentFile']));
4181
+ }
4182
+ return [];
4183
+ }
4184
+ partialScope() {
4185
+ if (isString(this['file'])) {
4186
+ let names;
4187
+ if (this.liquid.options.jekyllInclude) {
4188
+ names = ['include'];
4189
+ }
4190
+ else {
4191
+ names = Object.keys(this.hash.hash);
4192
+ if (this.withVar) {
4193
+ names.push([this['file'], this.withVar]);
4194
+ }
4195
+ }
4196
+ return { name: this['file'], isolated: false, scope: names };
4197
+ }
4198
+ }
4199
+ *arguments() {
4200
+ yield* Object.values(this.hash.hash).filter(isValueToken);
4201
+ if (isValueToken(this['file'])) {
4202
+ yield this['file'];
4203
+ }
4204
+ if (isValueToken(this.withVar)) {
4205
+ yield this.withVar;
4206
+ }
4207
+ }
3713
4208
  }
3714
4209
 
3715
4210
  class DecrementTag extends Tag {
3716
4211
  constructor(token, remainTokens, liquid) {
3717
4212
  super(token, remainTokens, liquid);
3718
- this.variable = this.tokenizer.readIdentifier().content;
4213
+ this.identifier = this.tokenizer.readIdentifier();
4214
+ this.variable = this.identifier.content;
3719
4215
  }
3720
4216
  render(context, emitter) {
3721
4217
  const scope = context.environments;
@@ -3724,6 +4220,9 @@ class DecrementTag extends Tag {
3724
4220
  }
3725
4221
  emitter.write(stringify(--scope[this.variable]));
3726
4222
  }
4223
+ *localScope() {
4224
+ yield this.identifier;
4225
+ }
3727
4226
  }
3728
4227
 
3729
4228
  class CycleTag extends Tag {
@@ -3761,6 +4260,12 @@ class CycleTag extends Tag {
3761
4260
  groups[fingerprint] = idx;
3762
4261
  return yield evalToken(candidate, ctx);
3763
4262
  }
4263
+ *arguments() {
4264
+ yield* this.candidates;
4265
+ if (this.group) {
4266
+ yield this.group;
4267
+ }
4268
+ }
3764
4269
  }
3765
4270
 
3766
4271
  class IfTag extends Tag {
@@ -3770,13 +4275,13 @@ class IfTag extends Tag {
3770
4275
  let p = [];
3771
4276
  parser.parseStream(remainTokens)
3772
4277
  .on('start', () => this.branches.push({
3773
- value: new Value(tagToken.args, this.liquid),
4278
+ value: new Value(tagToken.tokenizer.readFilteredValue(), this.liquid),
3774
4279
  templates: (p = [])
3775
4280
  }))
3776
4281
  .on('tag:elsif', (token) => {
3777
4282
  assert(!this.elseTemplates, 'unexpected elsif after else');
3778
4283
  this.branches.push({
3779
- value: new Value(token.args, this.liquid),
4284
+ value: new Value(token.tokenizer.readFilteredValue(), this.liquid),
3780
4285
  templates: (p = [])
3781
4286
  });
3782
4287
  })
@@ -3801,12 +4306,23 @@ class IfTag extends Tag {
3801
4306
  }
3802
4307
  yield r.renderTemplates(this.elseTemplates || [], ctx, emitter);
3803
4308
  }
4309
+ *children() {
4310
+ const templates = this.branches.flatMap(b => b.templates);
4311
+ if (this.elseTemplates) {
4312
+ templates.push(...this.elseTemplates);
4313
+ }
4314
+ return templates;
4315
+ }
4316
+ arguments() {
4317
+ return this.branches.map(b => b.value);
4318
+ }
3804
4319
  }
3805
4320
 
3806
4321
  class IncrementTag extends Tag {
3807
4322
  constructor(token, remainTokens, liquid) {
3808
4323
  super(token, remainTokens, liquid);
3809
- this.variable = this.tokenizer.readIdentifier().content;
4324
+ this.identifier = this.tokenizer.readIdentifier();
4325
+ this.variable = this.identifier.content;
3810
4326
  }
3811
4327
  render(context, emitter) {
3812
4328
  const scope = context.environments;
@@ -3817,6 +4333,9 @@ class IncrementTag extends Tag {
3817
4333
  scope[this.variable]++;
3818
4334
  emitter.write(stringify(val));
3819
4335
  }
4336
+ *localScope() {
4337
+ yield this.identifier;
4338
+ }
3820
4339
  }
3821
4340
 
3822
4341
  class LayoutTag extends Tag {
@@ -3824,7 +4343,7 @@ class LayoutTag extends Tag {
3824
4343
  super(token, remainTokens, liquid);
3825
4344
  this.file = parseFilePath(this.tokenizer, this.liquid, parser);
3826
4345
  this['currentFile'] = token.file;
3827
- this.args = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
4346
+ this.args = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
3828
4347
  this.templates = parser.parseTokens(remainTokens);
3829
4348
  }
3830
4349
  *render(ctx, emitter) {
@@ -3851,6 +4370,28 @@ class LayoutTag extends Tag {
3851
4370
  yield renderer.renderTemplates(templates, ctx, emitter);
3852
4371
  ctx.pop();
3853
4372
  }
4373
+ *children(partials) {
4374
+ const templates = this.templates.slice();
4375
+ if (partials && isString(this.file)) {
4376
+ templates.push(...(yield this.liquid._parsePartialFile(this.file, true, this['currentFile'])));
4377
+ }
4378
+ return templates;
4379
+ }
4380
+ *arguments() {
4381
+ for (const v of Object.values(this.args.hash)) {
4382
+ if (isValueToken(v)) {
4383
+ yield v;
4384
+ }
4385
+ }
4386
+ if (isValueToken(this.file)) {
4387
+ yield this.file;
4388
+ }
4389
+ }
4390
+ partialScope() {
4391
+ if (isString(this.file)) {
4392
+ return { name: this.file, isolated: false, scope: Object.keys(this.args.hash) };
4393
+ }
4394
+ }
3854
4395
  }
3855
4396
 
3856
4397
  class BlockTag extends Tag {
@@ -3890,6 +4431,12 @@ class BlockTag extends Tag {
3890
4431
  ? (superBlock, emitter) => renderChild(new BlockDrop(() => renderCurrent(superBlock, emitter)), emitter)
3891
4432
  : renderCurrent;
3892
4433
  }
4434
+ *children() {
4435
+ return this.templates;
4436
+ }
4437
+ blockScope() {
4438
+ return ['block'];
4439
+ }
3893
4440
  }
3894
4441
 
3895
4442
  class RawTag extends Tag {
@@ -3944,7 +4491,7 @@ class TablerowTag extends Tag {
3944
4491
  }
3945
4492
  this.variable = variable.content;
3946
4493
  this.collection = collectionToken;
3947
- this.args = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
4494
+ this.args = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
3948
4495
  this.templates = [];
3949
4496
  let p;
3950
4497
  const stream = parser.parseStream(remainTokens)
@@ -3982,6 +4529,20 @@ class TablerowTag extends Tag {
3982
4529
  emitter.write('</tr>');
3983
4530
  ctx.pop();
3984
4531
  }
4532
+ *children() {
4533
+ return this.templates;
4534
+ }
4535
+ *arguments() {
4536
+ yield this.collection;
4537
+ for (const v of Object.values(this.args.hash)) {
4538
+ if (isValueToken(v)) {
4539
+ yield v;
4540
+ }
4541
+ }
4542
+ }
4543
+ blockScope() {
4544
+ return [this.variable, 'tablerowloop'];
4545
+ }
3985
4546
  }
3986
4547
 
3987
4548
  class UnlessTag extends Tag {
@@ -3993,7 +4554,7 @@ class UnlessTag extends Tag {
3993
4554
  let elseCount = 0;
3994
4555
  parser.parseStream(remainTokens)
3995
4556
  .on('start', () => this.branches.push({
3996
- value: new Value(tagToken.args, this.liquid),
4557
+ value: new Value(tagToken.tokenizer.readFilteredValue(), this.liquid),
3997
4558
  test: isFalsy,
3998
4559
  templates: (p = [])
3999
4560
  }))
@@ -4003,7 +4564,7 @@ class UnlessTag extends Tag {
4003
4564
  return;
4004
4565
  }
4005
4566
  this.branches.push({
4006
- value: new Value(token.args, this.liquid),
4567
+ value: new Value(token.tokenizer.readFilteredValue(), this.liquid),
4007
4568
  test: isTruthy,
4008
4569
  templates: (p = [])
4009
4570
  });
@@ -4032,17 +4593,27 @@ class UnlessTag extends Tag {
4032
4593
  }
4033
4594
  yield r.renderTemplates(this.elseTemplates, ctx, emitter);
4034
4595
  }
4596
+ *children() {
4597
+ const children = this.branches.flatMap(b => b.templates);
4598
+ if (this.elseTemplates) {
4599
+ children.push(...this.elseTemplates);
4600
+ }
4601
+ return children;
4602
+ }
4603
+ arguments() {
4604
+ return this.branches.map(b => b.value);
4605
+ }
4035
4606
  }
4036
4607
 
4037
4608
  class BreakTag extends Tag {
4038
- render(ctx, emitter) {
4039
- emitter['break'] = true;
4609
+ render(ctx, _emitter) {
4610
+ ctx.breakCalled = true;
4040
4611
  }
4041
4612
  }
4042
4613
 
4043
4614
  class ContinueTag extends Tag {
4044
- render(ctx, emitter) {
4045
- emitter['continue'] = true;
4615
+ render(ctx, _emitter) {
4616
+ ctx.continueCalled = true;
4046
4617
  }
4047
4618
  }
4048
4619
 
@@ -4060,6 +4631,11 @@ class EchoTag extends Tag {
4060
4631
  const val = yield this.value.value(ctx, false);
4061
4632
  emitter.write(val);
4062
4633
  }
4634
+ *arguments() {
4635
+ if (this.value) {
4636
+ yield this.value;
4637
+ }
4638
+ }
4063
4639
  }
4064
4640
 
4065
4641
  class LiquidTag extends Tag {
@@ -4071,6 +4647,9 @@ class LiquidTag extends Tag {
4071
4647
  *render(ctx, emitter) {
4072
4648
  yield this.liquid.renderer.renderTemplates(this.templates, ctx, emitter);
4073
4649
  }
4650
+ *children() {
4651
+ return this.templates;
4652
+ }
4074
4653
  }
4075
4654
 
4076
4655
  class InlineCommentTag extends Tag {
@@ -4221,9 +4800,97 @@ class Liquid {
4221
4800
  self.renderFile(filePath, ctx).then(html => callback(null, html), callback);
4222
4801
  };
4223
4802
  }
4803
+ analyze(template, options = {}) {
4804
+ return __awaiter(this, void 0, void 0, function* () {
4805
+ return analyze(template, options);
4806
+ });
4807
+ }
4808
+ analyzeSync(template, options = {}) {
4809
+ return analyzeSync(template, options);
4810
+ }
4811
+ parseAndAnalyze(html, filename, options = {}) {
4812
+ return __awaiter(this, void 0, void 0, function* () {
4813
+ return analyze(this.parse(html, filename), options);
4814
+ });
4815
+ }
4816
+ parseAndAnalyzeSync(html, filename, options = {}) {
4817
+ return analyzeSync(this.parse(html, filename), options);
4818
+ }
4819
+ /** Return an array of all variables without their properties. */
4820
+ variables(template, options = {}) {
4821
+ return __awaiter(this, void 0, void 0, function* () {
4822
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4823
+ return Object.keys(analysis.variables);
4824
+ });
4825
+ }
4826
+ /** Return an array of all variables without their properties. */
4827
+ variablesSync(template, options = {}) {
4828
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4829
+ return Object.keys(analysis.variables);
4830
+ }
4831
+ /** Return an array of all variables including their properties/paths. */
4832
+ fullVariables(template, options = {}) {
4833
+ return __awaiter(this, void 0, void 0, function* () {
4834
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4835
+ return Array.from(new Set(Object.values(analysis.variables).flatMap((a) => a.map((v) => String(v)))));
4836
+ });
4837
+ }
4838
+ /** Return an array of all variables including their properties/paths. */
4839
+ fullVariablesSync(template, options = {}) {
4840
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4841
+ return Array.from(new Set(Object.values(analysis.variables).flatMap((a) => a.map((v) => String(v)))));
4842
+ }
4843
+ /** Return an array of all variables, each as an array of properties/segments. */
4844
+ variableSegments(template, options = {}) {
4845
+ return __awaiter(this, void 0, void 0, function* () {
4846
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4847
+ return Array.from(strictUniq(Object.values(analysis.variables).flatMap((a) => a.map((v) => v.toArray()))));
4848
+ });
4849
+ }
4850
+ /** Return an array of all variables, each as an array of properties/segments. */
4851
+ variableSegmentsSync(template, options = {}) {
4852
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4853
+ return Array.from(strictUniq(Object.values(analysis.variables).flatMap((a) => a.map((v) => v.toArray()))));
4854
+ }
4855
+ /** Return an array of all expected context variables without their properties. */
4856
+ globalVariables(template, options = {}) {
4857
+ return __awaiter(this, void 0, void 0, function* () {
4858
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4859
+ return Object.keys(analysis.globals);
4860
+ });
4861
+ }
4862
+ /** Return an array of all expected context variables without their properties. */
4863
+ globalVariablesSync(template, options = {}) {
4864
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4865
+ return Object.keys(analysis.globals);
4866
+ }
4867
+ /** Return an array of all expected context variables including their properties/paths. */
4868
+ globalFullVariables(template, options = {}) {
4869
+ return __awaiter(this, void 0, void 0, function* () {
4870
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4871
+ return Array.from(new Set(Object.values(analysis.globals).flatMap((a) => a.map((v) => String(v)))));
4872
+ });
4873
+ }
4874
+ /** Return an array of all expected context variables including their properties/paths. */
4875
+ globalFullVariablesSync(template, options = {}) {
4876
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4877
+ return Array.from(new Set(Object.values(analysis.globals).flatMap((a) => a.map((v) => String(v)))));
4878
+ }
4879
+ /** Return an array of all expected context variables, each as an array of properties/segments. */
4880
+ globalVariableSegments(template, options = {}) {
4881
+ return __awaiter(this, void 0, void 0, function* () {
4882
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4883
+ return Array.from(strictUniq(Object.values(analysis.globals).flatMap((a) => a.map((v) => v.toArray()))));
4884
+ });
4885
+ }
4886
+ /** Return an array of all expected context variables, each as an array of properties/segments. */
4887
+ globalVariableSegmentsSync(template, options = {}) {
4888
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4889
+ return Array.from(strictUniq(Object.values(analysis.globals).flatMap((a) => a.map((v) => v.toArray()))));
4890
+ }
4224
4891
  }
4225
4892
 
4226
4893
  /* istanbul ignore file */
4227
4894
  const version = '[VI]{version}[/VI]';
4228
4895
 
4229
- export { AssertionError, AssignTag, BlockTag, BreakTag, CaptureTag, CaseTag, CommentTag, Context, ContinueTag, CycleTag, DecrementTag, Drop, EchoTag, Expression, Filter, ForTag, Hash, IfTag, IncludeTag, IncrementTag, InlineCommentTag, LayoutTag, Liquid, LiquidError, LiquidTag, Output, ParseError, ParseStream, RawTag, RenderError, RenderTag, TablerowTag, Tag, TagToken, Token, TokenKind, TokenizationError, Tokenizer, typeGuards as TypeGuards, UndefinedVariableError, UnlessTag, Value, assert, createTrie, defaultOperators, defaultOptions, evalQuotedToken, evalToken, filters, isFalsy, isTruthy, tags, toPromise, toValue, toValueSync, version };
4896
+ export { AssertionError, AssignTag, BlockTag, BreakTag, CaptureTag, CaseTag, CommentTag, Context, ContinueTag, CycleTag, DecrementTag, Drop, EchoTag, Expression, Filter, ForTag, Hash, IfTag, IncludeTag, IncrementTag, InlineCommentTag, LayoutTag, Liquid, LiquidError, LiquidTag, Output, ParseError, ParseStream, Parser, RawTag, RenderError, RenderTag, TablerowTag, Tag, TagToken, Token, TokenKind, TokenizationError, Tokenizer, typeGuards as TypeGuards, UndefinedVariableError, UnlessTag, Value, Variable, analyze, analyzeSync, assert, createTrie, defaultOperators, defaultOptions, evalQuotedToken, evalToken, filters, isFalsy, isTruthy, tags, toPromise, toValue, toValueSync, version };