@skeptools/skep-organization-project 0.0.16 → 0.0.18

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 +29 -4
  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 +4 -4
@@ -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
  class Token {
@@ -111,6 +111,9 @@ function isArray(value) {
111
111
  // be compatible with IE 8
112
112
  return toString$1.call(value) === '[object Array]';
113
113
  }
114
+ function isArrayLike(value) {
115
+ return value && isNumber(value.length);
116
+ }
114
117
  function isIterable(value) {
115
118
  return isObject(value) && Symbol.iterator in value;
116
119
  }
@@ -196,6 +199,17 @@ function argumentsToValue(fn) {
196
199
  }
197
200
  function escapeRegExp(text) {
198
201
  return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
202
+ }
203
+ /** Return an array containing unique elements from _array_. Works with nested arrays and objects. */
204
+ function* strictUniq(array) {
205
+ const seen = new Set();
206
+ for (const element of array) {
207
+ const key = JSON.stringify(element);
208
+ if (!seen.has(key)) {
209
+ seen.add(key);
210
+ yield element;
211
+ }
212
+ }
199
213
  }
200
214
 
201
215
  /**
@@ -396,6 +410,9 @@ class EmptyDrop extends Drop {
396
410
  valueOf() {
397
411
  return '';
398
412
  }
413
+ static is(value) {
414
+ return value instanceof EmptyDrop;
415
+ }
399
416
  }
400
417
 
401
418
  class BlankDrop extends EmptyDrop {
@@ -408,6 +425,9 @@ class BlankDrop extends EmptyDrop {
408
425
  return /^\s*$/.test(value);
409
426
  return super.equals(value);
410
427
  }
428
+ static is(value) {
429
+ return value instanceof BlankDrop;
430
+ }
411
431
  }
412
432
 
413
433
  class ForloopDrop extends Drop {
@@ -732,7 +752,11 @@ function getDateTimeFormat() {
732
752
 
733
753
  // one minute in milliseconds
734
754
  const OneMinute = 60000;
735
- const ISO8601_TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):(\d{2}))$/;
755
+ /**
756
+ * Need support both ISO8601 and RFC2822 as in major browsers & NodeJS
757
+ * RFC2822: https://datatracker.ietf.org/doc/html/rfc2822#section-3.3
758
+ */
759
+ const TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):?(\d{2}))$/;
736
760
  const monthNames = [
737
761
  'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
738
762
  'September', 'October', 'November', 'December'
@@ -849,7 +873,7 @@ class LiquidDate {
849
873
  * Given that a template is expected to be parsed fewer times than rendered.
850
874
  */
851
875
  static createDateFixedToTimezone(dateString, locale) {
852
- const m = dateString.match(ISO8601_TIMEZONE_PATTERN);
876
+ const m = dateString.match(TIMEZONE_PATTERN);
853
877
  // representing a UTC timestamp
854
878
  if (m && m[1] === 'Z') {
855
879
  return new LiquidDate(+new Date(dateString), locale, 0);
@@ -1135,7 +1159,9 @@ class LiquidTagToken extends DelimitedToken {
1135
1159
  this.name = this.tokenizer.readTagName();
1136
1160
  this.tokenizer.assert(this.name, 'illegal liquid tag syntax');
1137
1161
  this.tokenizer.skipBlank();
1138
- this.args = this.tokenizer.remaining();
1162
+ }
1163
+ get args() {
1164
+ return this.tokenizer.input.slice(this.tokenizer.p, this.contentRange[1]);
1139
1165
  }
1140
1166
  }
1141
1167
 
@@ -1220,7 +1246,7 @@ class Render {
1220
1246
  const html = yield tpl.render(ctx, emitter);
1221
1247
  // if not, it'll return an `html`, write to the emitter for it
1222
1248
  html && emitter.write(html);
1223
- if (emitter['break'] || emitter['continue'])
1249
+ if (ctx.breakCalled || ctx.continueCalled)
1224
1250
  break;
1225
1251
  }
1226
1252
  catch (e) {
@@ -1304,6 +1330,7 @@ function evalQuotedToken(token) {
1304
1330
  function* evalRangeToken(token, ctx) {
1305
1331
  const low = yield evalToken(token.lhs, ctx);
1306
1332
  const high = yield evalToken(token.rhs, ctx);
1333
+ ctx.memoryLimit.use(high - low + 1);
1307
1334
  return range(+low, +high + 1);
1308
1335
  }
1309
1336
  function* toPostfix(tokens) {
@@ -1395,6 +1422,9 @@ function arrayEquals(lhs, rhs) {
1395
1422
  if (lhs.length !== rhs.length)
1396
1423
  return false;
1397
1424
  return !lhs.some((value, i) => !equals(value, rhs[i]));
1425
+ }
1426
+ function arrayIncludes(arr, item) {
1427
+ return arr.some(value => equals(value, item));
1398
1428
  }
1399
1429
 
1400
1430
  class Node {
@@ -2300,9 +2330,9 @@ class Tag extends TemplateImpl {
2300
2330
  * hash['reversed'] === undefined
2301
2331
  */
2302
2332
  class Hash {
2303
- constructor(markup, jekyllStyle) {
2333
+ constructor(input, jekyllStyle) {
2304
2334
  this.hash = {};
2305
- const tokenizer = new Tokenizer(markup, {});
2335
+ const tokenizer = input instanceof Tokenizer ? input : new Tokenizer(input, {});
2306
2336
  for (const hash of tokenizer.readHashes(jekyllStyle)) {
2307
2337
  this.hash[hash.name.content] = hash.value;
2308
2338
  }
@@ -2402,6 +2432,9 @@ class Output extends TemplateImpl {
2402
2432
  const val = yield this.value.value(ctx, false);
2403
2433
  emitter.write(val);
2404
2434
  }
2435
+ *arguments() {
2436
+ yield this.value;
2437
+ }
2405
2438
  }
2406
2439
 
2407
2440
  class HTML extends TemplateImpl {
@@ -2414,6 +2447,336 @@ class HTML extends TemplateImpl {
2414
2447
  }
2415
2448
  }
2416
2449
 
2450
+ /**
2451
+ * A variable's segments and location, which can be coerced to a string.
2452
+ */
2453
+ class Variable {
2454
+ constructor(segments, location) {
2455
+ this.segments = segments;
2456
+ this.location = location;
2457
+ }
2458
+ toString() {
2459
+ return segmentsString(this.segments, true);
2460
+ }
2461
+ /** Return this variable's segments as an array, possibly with nested arrays for nested paths. */
2462
+ toArray() {
2463
+ function* _visit(...segments) {
2464
+ for (const segment of segments) {
2465
+ if (segment instanceof Variable) {
2466
+ yield Array.from(_visit(...segment.segments));
2467
+ }
2468
+ else {
2469
+ yield segment;
2470
+ }
2471
+ }
2472
+ }
2473
+ return Array.from(_visit(...this.segments));
2474
+ }
2475
+ }
2476
+ /**
2477
+ * Group variables by the string representation of their root segment.
2478
+ */
2479
+ class VariableMap {
2480
+ constructor() {
2481
+ this.map = new Map();
2482
+ }
2483
+ get(key) {
2484
+ const k = segmentsString([key.segments[0]]);
2485
+ if (!this.map.has(k)) {
2486
+ this.map.set(k, []);
2487
+ }
2488
+ return this.map.get(k);
2489
+ }
2490
+ has(key) {
2491
+ return this.map.has(segmentsString([key.segments[0]]));
2492
+ }
2493
+ push(variable) {
2494
+ this.get(variable).push(variable);
2495
+ }
2496
+ asObject() {
2497
+ return Object.fromEntries(this.map);
2498
+ }
2499
+ }
2500
+ const defaultStaticAnalysisOptions = {
2501
+ partials: true
2502
+ };
2503
+ function* _analyze(templates, partials, sync) {
2504
+ const variables = new VariableMap();
2505
+ const globals = new VariableMap();
2506
+ const locals = new VariableMap();
2507
+ const rootScope = new DummyScope(new Set());
2508
+ // Names of partial templates that we've already analyzed.
2509
+ const seen = new Set();
2510
+ function updateVariables(variable, scope) {
2511
+ variables.push(variable);
2512
+ const aliased = scope.alias(variable);
2513
+ if (aliased !== undefined) {
2514
+ const root = aliased.segments[0];
2515
+ // TODO: What if a a template renders a rendered template? Do we need scope.parent?
2516
+ if (isString(root) && !rootScope.has(root)) {
2517
+ globals.push(aliased);
2518
+ }
2519
+ }
2520
+ else {
2521
+ const root = variable.segments[0];
2522
+ if (isString(root) && !scope.has(root)) {
2523
+ globals.push(variable);
2524
+ }
2525
+ }
2526
+ // Recurse for nested Variables
2527
+ for (const segment of variable.segments) {
2528
+ if (segment instanceof Variable) {
2529
+ updateVariables(segment, scope);
2530
+ }
2531
+ }
2532
+ }
2533
+ function* visit(template, scope) {
2534
+ if (template.arguments) {
2535
+ for (const arg of template.arguments()) {
2536
+ for (const variable of extractVariables(arg)) {
2537
+ updateVariables(variable, scope);
2538
+ }
2539
+ }
2540
+ }
2541
+ if (template.localScope) {
2542
+ for (const ident of template.localScope()) {
2543
+ scope.add(ident.content);
2544
+ scope.deleteAlias(ident.content);
2545
+ const [row, col] = ident.getPosition();
2546
+ locals.push(new Variable([ident.content], { row, col, file: ident.file }));
2547
+ }
2548
+ }
2549
+ if (template.children) {
2550
+ if (template.partialScope) {
2551
+ const partial = template.partialScope();
2552
+ if (partial === undefined) {
2553
+ // Layouts, for example, can have children that are not partials.
2554
+ for (const child of (yield template.children(partials, sync))) {
2555
+ yield visit(child, scope);
2556
+ }
2557
+ return;
2558
+ }
2559
+ if (seen.has(partial.name))
2560
+ return;
2561
+ const partialScopeNames = new Set();
2562
+ const partialScope = partial.isolated
2563
+ ? new DummyScope(partialScopeNames)
2564
+ : scope.push(partialScopeNames);
2565
+ for (const name of partial.scope) {
2566
+ if (isString(name)) {
2567
+ partialScopeNames.add(name);
2568
+ }
2569
+ else {
2570
+ const [alias, argument] = name;
2571
+ partialScopeNames.add(alias);
2572
+ const variables = Array.from(extractVariables(argument));
2573
+ if (variables.length) {
2574
+ partialScope.setAlias(alias, variables[0].segments);
2575
+ }
2576
+ }
2577
+ }
2578
+ for (const child of (yield template.children(partials, sync))) {
2579
+ yield visit(child, partialScope);
2580
+ seen.add(partial.name);
2581
+ }
2582
+ partialScope.pop();
2583
+ }
2584
+ else {
2585
+ if (template.blockScope) {
2586
+ scope.push(new Set(template.blockScope()));
2587
+ }
2588
+ for (const child of (yield template.children(partials, sync))) {
2589
+ yield visit(child, scope);
2590
+ }
2591
+ if (template.blockScope) {
2592
+ scope.pop();
2593
+ }
2594
+ }
2595
+ }
2596
+ }
2597
+ for (const template of templates) {
2598
+ yield visit(template, rootScope);
2599
+ }
2600
+ return {
2601
+ variables: variables.asObject(),
2602
+ globals: globals.asObject(),
2603
+ locals: locals.asObject()
2604
+ };
2605
+ }
2606
+ /**
2607
+ * Statically analyze a template and report variable usage.
2608
+ */
2609
+ function analyze(template, options = {}) {
2610
+ const opts = Object.assign(Object.assign({}, defaultStaticAnalysisOptions), options);
2611
+ return toPromise(_analyze(template, opts.partials, false));
2612
+ }
2613
+ /**
2614
+ * Statically analyze a template and report variable usage.
2615
+ */
2616
+ function analyzeSync(template, options = {}) {
2617
+ const opts = Object.assign(Object.assign({}, defaultStaticAnalysisOptions), options);
2618
+ return toValueSync(_analyze(template, opts.partials, true));
2619
+ }
2620
+ /**
2621
+ * A stack to manage scopes while traversing templates during static analysis.
2622
+ */
2623
+ class DummyScope {
2624
+ constructor(globals) {
2625
+ this.stack = [{ names: globals, aliases: new Map() }];
2626
+ }
2627
+ /** Return true if `name` is in scope. */
2628
+ has(name) {
2629
+ for (const scope of this.stack) {
2630
+ if (scope.names.has(name)) {
2631
+ return true;
2632
+ }
2633
+ }
2634
+ return false;
2635
+ }
2636
+ push(scope) {
2637
+ this.stack.push({ names: scope, aliases: new Map() });
2638
+ return this;
2639
+ }
2640
+ pop() {
2641
+ var _a;
2642
+ return (_a = this.stack.pop()) === null || _a === void 0 ? void 0 : _a.names;
2643
+ }
2644
+ // Add a name to the template scope.
2645
+ add(name) {
2646
+ this.stack[0].names.add(name);
2647
+ }
2648
+ /** Return the variable that `variable` aliases, or `variable` if it doesn't alias anything. */
2649
+ alias(variable) {
2650
+ const root = variable.segments[0];
2651
+ if (!isString(root))
2652
+ return undefined;
2653
+ const alias = this.getAlias(root);
2654
+ if (alias === undefined)
2655
+ return undefined;
2656
+ return new Variable([...alias, ...variable.segments.slice(1)], variable.location);
2657
+ }
2658
+ // TODO: `from` could be a path with multiple segments, like `include.x`.
2659
+ setAlias(from, to) {
2660
+ this.stack[this.stack.length - 1].aliases.set(from, to);
2661
+ }
2662
+ deleteAlias(name) {
2663
+ this.stack[this.stack.length - 1].aliases.delete(name);
2664
+ }
2665
+ getAlias(name) {
2666
+ for (const scope of this.stack) {
2667
+ if (scope.aliases.has(name)) {
2668
+ return scope.aliases.get(name);
2669
+ }
2670
+ // If a scope has defined `name`, then it masks aliases in parent scopes.
2671
+ if (scope.names.has(name)) {
2672
+ return undefined;
2673
+ }
2674
+ }
2675
+ return undefined;
2676
+ }
2677
+ }
2678
+ function* extractVariables(value) {
2679
+ if (isValueToken(value)) {
2680
+ yield* extractValueTokenVariables(value);
2681
+ }
2682
+ else if (value instanceof Value) {
2683
+ yield* extractFilteredValueVariables(value);
2684
+ }
2685
+ }
2686
+ function* extractFilteredValueVariables(value) {
2687
+ for (const token of value.initial.postfix) {
2688
+ if (isValueToken(token)) {
2689
+ yield* extractValueTokenVariables(token);
2690
+ }
2691
+ }
2692
+ for (const filter of value.filters) {
2693
+ for (const arg of filter.args) {
2694
+ if (isKeyValuePair(arg) && arg[1]) {
2695
+ yield* extractValueTokenVariables(arg[1]);
2696
+ }
2697
+ else if (isValueToken(arg)) {
2698
+ yield* extractValueTokenVariables(arg);
2699
+ }
2700
+ }
2701
+ }
2702
+ }
2703
+ function* extractValueTokenVariables(token) {
2704
+ if (isRangeToken(token)) {
2705
+ yield* extractValueTokenVariables(token.lhs);
2706
+ yield* extractValueTokenVariables(token.rhs);
2707
+ }
2708
+ else if (isPropertyAccessToken(token)) {
2709
+ yield extractPropertyAccessVariable(token);
2710
+ }
2711
+ }
2712
+ function extractPropertyAccessVariable(token) {
2713
+ const segments = [];
2714
+ // token is not guaranteed to have `file` set. We'll try to get it from a prop if not.
2715
+ let file = token.file;
2716
+ // Here we're flattening the first segment of a path if it is a nested path.
2717
+ const root = token.props[0];
2718
+ file = file || root.file;
2719
+ if (isQuotedToken(root) || isNumberToken(root) || isWordToken(root)) {
2720
+ segments.push(root.content);
2721
+ }
2722
+ else if (isPropertyAccessToken(root)) {
2723
+ // Flatten paths that start with a nested path.
2724
+ segments.push(...extractPropertyAccessVariable(root).segments);
2725
+ }
2726
+ for (const prop of token.props.slice(1)) {
2727
+ file = file || prop.file;
2728
+ if (isQuotedToken(prop) || isNumberToken(prop) || isWordToken(prop)) {
2729
+ segments.push(prop.content);
2730
+ }
2731
+ else if (isPropertyAccessToken(prop)) {
2732
+ segments.push(extractPropertyAccessVariable(prop));
2733
+ }
2734
+ }
2735
+ const [row, col] = token.getPosition();
2736
+ return new Variable(segments, {
2737
+ row,
2738
+ col,
2739
+ file
2740
+ });
2741
+ }
2742
+ // This is used to detect segments that can be represented with dot notation
2743
+ // when creating a string representation of VariableSegments.
2744
+ const RE_PROPERTY = /^[\u0080-\uFFFFa-zA-Z_][\u0080-\uFFFFa-zA-Z0-9_-]*$/;
2745
+ /**
2746
+ * Return a string representation of segments using dot notation where possible.
2747
+ * @param segments - The property names and array indices that make up a path to a variable.
2748
+ * @param bracketedRoot - If false (the default), don't surround the root segment with square brackets.
2749
+ */
2750
+ function segmentsString(segments, bracketedRoot = false) {
2751
+ const buf = [];
2752
+ const root = segments[0];
2753
+ if (isString(root)) {
2754
+ if (!bracketedRoot || root.match(RE_PROPERTY)) {
2755
+ buf.push(`${root}`);
2756
+ }
2757
+ else {
2758
+ buf.push(`['${root}']`);
2759
+ }
2760
+ }
2761
+ for (const segment of segments.slice(1)) {
2762
+ if (segment instanceof Variable) {
2763
+ buf.push(`[${segmentsString(segment.segments)}]`);
2764
+ }
2765
+ else if (isString(segment)) {
2766
+ if (segment.match(RE_PROPERTY)) {
2767
+ buf.push(`.${segment}`);
2768
+ }
2769
+ else {
2770
+ buf.push(`['${segment}']`);
2771
+ }
2772
+ }
2773
+ else {
2774
+ buf.push(`[${segment}]`);
2775
+ }
2776
+ }
2777
+ return buf.join('');
2778
+ }
2779
+
2417
2780
  var LookupType;
2418
2781
  (function (LookupType) {
2419
2782
  LookupType["Partials"] = "partials";
@@ -2613,6 +2976,10 @@ function isWordToken(val) {
2613
2976
  function isRangeToken(val) {
2614
2977
  return getKind(val) === TokenKind.Range;
2615
2978
  }
2979
+ function isValueToken(val) {
2980
+ // valueTokenBitMask = TokenKind.Number | TokenKind.Literal | TokenKind.Quoted | TokenKind.PropertyAccess | TokenKind.Range
2981
+ return (getKind(val) & 1667) > 0;
2982
+ }
2616
2983
  function getKind(val) {
2617
2984
  return val ? val.kind : -1;
2618
2985
  }
@@ -2629,7 +2996,8 @@ var typeGuards = /*#__PURE__*/Object.freeze({
2629
2996
  isNumberToken: isNumberToken,
2630
2997
  isPropertyAccessToken: isPropertyAccessToken,
2631
2998
  isWordToken: isWordToken,
2632
- isRangeToken: isRangeToken
2999
+ isRangeToken: isRangeToken,
3000
+ isValueToken: isValueToken
2633
3001
  });
2634
3002
 
2635
3003
  class Context {
@@ -2641,6 +3009,8 @@ class Context {
2641
3009
  */
2642
3010
  this.scopes = [{}];
2643
3011
  this.registers = {};
3012
+ this.breakCalled = false;
3013
+ this.continueCalled = false;
2644
3014
  this.sync = !!renderOptions.sync;
2645
3015
  this.opts = opts;
2646
3016
  this.globals = (_a = renderOptions.globals) !== null && _a !== void 0 ? _a : opts.globals;
@@ -2676,7 +3046,7 @@ class Context {
2676
3046
  return toValueSync(this._get(paths));
2677
3047
  }
2678
3048
  *_get(paths) {
2679
- const scope = this.findScope(paths[0]);
3049
+ const scope = this.findScope(paths[0]); // first prop should always be a string
2680
3050
  return yield this._getFromScope(scope, paths);
2681
3051
  }
2682
3052
  /**
@@ -2728,6 +3098,7 @@ class Context {
2728
3098
  }
2729
3099
  function readProperty(obj, key, ownPropertyOnly) {
2730
3100
  obj = toLiquid(obj);
3101
+ key = toValue(key);
2731
3102
  if (isNil(obj))
2732
3103
  return obj;
2733
3104
  if (isArray(obj) && key < 0)
@@ -2875,8 +3246,8 @@ const join = argumentsToValue(function (v, arg) {
2875
3246
  this.context.memoryLimit.use(complexity);
2876
3247
  return array.join(sep);
2877
3248
  });
2878
- const last$1 = argumentsToValue((v) => isArray(v) ? last(v) : '');
2879
- const first = argumentsToValue((v) => isArray(v) ? v[0] : '');
3249
+ const last$1 = argumentsToValue((v) => isArrayLike(v) ? last(v) : '');
3250
+ const first = argumentsToValue((v) => isArrayLike(v) ? v[0] : '');
2880
3251
  const reverse = argumentsToValue(function (v) {
2881
3252
  const array = toArray(v);
2882
3253
  this.context.memoryLimit.use(array.length);
@@ -2977,10 +3348,13 @@ function* where(arr, property, expected) {
2977
3348
  for (const item of arr) {
2978
3349
  values.push(yield evalToken(token, this.context.spawn(item)));
2979
3350
  }
3351
+ const matcher = this.context.opts.jekyllWhere
3352
+ ? (v) => EmptyDrop.is(expected) ? equals(v, expected) : (isArray(v) ? arrayIncludes(v, expected) : equals(v, expected))
3353
+ : (v) => equals(v, expected);
2980
3354
  return arr.filter((_, i) => {
2981
3355
  if (expected === undefined)
2982
3356
  return isTruthy(values[i], this.context);
2983
- return equals(values[i], expected);
3357
+ return matcher(values[i]);
2984
3358
  });
2985
3359
  }
2986
3360
  function* where_exp(arr, itemName, exp) {
@@ -2997,7 +3371,7 @@ function* where_exp(arr, itemName, exp) {
2997
3371
  }
2998
3372
  function* group_by(arr, property) {
2999
3373
  const map = new Map();
3000
- arr = toArray(arr);
3374
+ arr = toEnumerable(arr);
3001
3375
  const token = new Tokenizer(stringify(property)).readScopeValue();
3002
3376
  this.context.memoryLimit.use(arr.length);
3003
3377
  for (const item of arr) {
@@ -3011,7 +3385,7 @@ function* group_by(arr, property) {
3011
3385
  function* group_by_exp(arr, itemName, exp) {
3012
3386
  const map = new Map();
3013
3387
  const keyTemplate = new Value(stringify(exp), this.liquid);
3014
- arr = toArray(arr);
3388
+ arr = toEnumerable(arr);
3015
3389
  this.context.memoryLimit.use(arr.length);
3016
3390
  for (const item of arr) {
3017
3391
  const key = yield keyTemplate.value(this.context.spawn({ [itemName]: item }));
@@ -3364,7 +3738,8 @@ const filters = Object.assign(Object.assign(Object.assign(Object.assign(Object.a
3364
3738
  class AssignTag extends Tag {
3365
3739
  constructor(token, remainTokens, liquid) {
3366
3740
  super(token, remainTokens, liquid);
3367
- this.key = this.tokenizer.readIdentifier().content;
3741
+ this.identifier = this.tokenizer.readIdentifier();
3742
+ this.key = this.identifier.content;
3368
3743
  this.tokenizer.assert(this.key, 'expected variable name');
3369
3744
  this.tokenizer.skipBlank();
3370
3745
  this.tokenizer.assert(this.tokenizer.peek() === '=', 'expected "="');
@@ -3374,6 +3749,12 @@ class AssignTag extends Tag {
3374
3749
  *render(ctx) {
3375
3750
  ctx.bottom()[this.key] = yield this.value.value(ctx, this.liquid.options.lenientIf);
3376
3751
  }
3752
+ *arguments() {
3753
+ yield this.value;
3754
+ }
3755
+ *localScope() {
3756
+ yield this.identifier;
3757
+ }
3377
3758
  }
3378
3759
 
3379
3760
  const MODIFIERS = ['offset', 'limit', 'reversed'];
@@ -3388,7 +3769,7 @@ class ForTag extends Tag {
3388
3769
  }
3389
3770
  this.variable = variable.content;
3390
3771
  this.collection = collection;
3391
- this.hash = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
3772
+ this.hash = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
3392
3773
  this.templates = [];
3393
3774
  this.elseTemplates = [];
3394
3775
  let p;
@@ -3426,16 +3807,33 @@ class ForTag extends Tag {
3426
3807
  ctx.push(scope);
3427
3808
  for (const item of collection) {
3428
3809
  scope[this.variable] = item;
3810
+ ctx.continueCalled = ctx.breakCalled = false;
3429
3811
  yield r.renderTemplates(this.templates, ctx, emitter);
3430
- if (emitter['break']) {
3431
- emitter['break'] = false;
3812
+ if (ctx.breakCalled)
3432
3813
  break;
3433
- }
3434
- emitter['continue'] = false;
3435
3814
  scope.forloop.next();
3436
3815
  }
3816
+ ctx.continueCalled = ctx.breakCalled = false;
3437
3817
  ctx.pop();
3438
3818
  }
3819
+ *children() {
3820
+ const templates = this.templates.slice();
3821
+ if (this.elseTemplates) {
3822
+ templates.push(...this.elseTemplates);
3823
+ }
3824
+ return templates;
3825
+ }
3826
+ *arguments() {
3827
+ yield this.collection;
3828
+ for (const v of Object.values(this.hash.hash)) {
3829
+ if (isValueToken(v)) {
3830
+ yield v;
3831
+ }
3832
+ }
3833
+ }
3834
+ blockScope() {
3835
+ return [this.variable, 'forloop'];
3836
+ }
3439
3837
  }
3440
3838
  function reversed(arr) {
3441
3839
  return [...arr].reverse();
@@ -3451,7 +3849,8 @@ class CaptureTag extends Tag {
3451
3849
  constructor(tagToken, remainTokens, liquid, parser) {
3452
3850
  super(tagToken, remainTokens, liquid);
3453
3851
  this.templates = [];
3454
- this.variable = this.readVariableName();
3852
+ this.identifier = this.readVariable();
3853
+ this.variable = this.identifier.content;
3455
3854
  while (remainTokens.length) {
3456
3855
  const token = remainTokens.shift();
3457
3856
  if (isTagToken(token) && token.name === 'endcapture')
@@ -3460,19 +3859,25 @@ class CaptureTag extends Tag {
3460
3859
  }
3461
3860
  throw new Error(`tag ${tagToken.getText()} not closed`);
3462
3861
  }
3862
+ readVariable() {
3863
+ let ident = this.tokenizer.readIdentifier();
3864
+ if (ident.content)
3865
+ return ident;
3866
+ ident = this.tokenizer.readQuoted();
3867
+ if (ident)
3868
+ return ident;
3869
+ throw this.tokenizer.error('invalid capture name');
3870
+ }
3463
3871
  *render(ctx) {
3464
3872
  const r = this.liquid.renderer;
3465
3873
  const html = yield r.renderTemplates(this.templates, ctx);
3466
3874
  ctx.bottom()[this.variable] = html;
3467
3875
  }
3468
- readVariableName() {
3469
- const word = this.tokenizer.readIdentifier().content;
3470
- if (word)
3471
- return word;
3472
- const quoted = this.tokenizer.readQuoted();
3473
- if (quoted)
3474
- return evalQuotedToken(quoted);
3475
- throw this.tokenizer.error('invalid capture name');
3876
+ *children() {
3877
+ return this.templates;
3878
+ }
3879
+ *localScope() {
3880
+ yield this.identifier;
3476
3881
  }
3477
3882
  }
3478
3883
 
@@ -3540,6 +3945,17 @@ class CaseTag extends Tag {
3540
3945
  yield r.renderTemplates(this.elseTemplates, ctx, emitter);
3541
3946
  }
3542
3947
  }
3948
+ *arguments() {
3949
+ yield this.value;
3950
+ yield* this.branches.flatMap(b => b.values);
3951
+ }
3952
+ *children() {
3953
+ const templates = this.branches.flatMap(b => b.templates);
3954
+ if (this.elseTemplates) {
3955
+ templates.push(...this.elseTemplates);
3956
+ }
3957
+ return templates;
3958
+ }
3543
3959
  }
3544
3960
 
3545
3961
  class CommentTag extends Tag {
@@ -3593,7 +4009,7 @@ class RenderTag extends Tag {
3593
4009
  tokenizer.p = begin;
3594
4010
  break;
3595
4011
  }
3596
- this.hash = new Hash(tokenizer.remaining(), liquid.options.keyValueSeparator);
4012
+ this.hash = new Hash(tokenizer, liquid.options.keyValueSeparator);
3597
4013
  }
3598
4014
  *render(ctx, emitter) {
3599
4015
  const { liquid, hash } = this;
@@ -3622,6 +4038,55 @@ class RenderTag extends Tag {
3622
4038
  yield liquid.renderer.renderTemplates(templates, childCtx, emitter);
3623
4039
  }
3624
4040
  }
4041
+ *children(partials, sync) {
4042
+ if (partials && isString(this['file'])) {
4043
+ return (yield this.liquid._parsePartialFile(this['file'], sync, this['currentFile']));
4044
+ }
4045
+ return [];
4046
+ }
4047
+ partialScope() {
4048
+ if (isString(this['file'])) {
4049
+ const names = Object.keys(this.hash.hash);
4050
+ if (this['with']) {
4051
+ const { value, alias } = this['with'];
4052
+ if (isString(alias)) {
4053
+ names.push([alias, value]);
4054
+ }
4055
+ else if (isString(this.file)) {
4056
+ names.push([this.file, value]);
4057
+ }
4058
+ }
4059
+ if (this['for']) {
4060
+ const { value, alias } = this['for'];
4061
+ if (isString(alias)) {
4062
+ names.push([alias, value]);
4063
+ }
4064
+ else if (isString(this.file)) {
4065
+ names.push([this.file, value]);
4066
+ }
4067
+ }
4068
+ return { name: this['file'], isolated: true, scope: names };
4069
+ }
4070
+ }
4071
+ *arguments() {
4072
+ for (const v of Object.values(this.hash.hash)) {
4073
+ if (isValueToken(v)) {
4074
+ yield v;
4075
+ }
4076
+ }
4077
+ if (this['with']) {
4078
+ const { value } = this['with'];
4079
+ if (isValueToken(value)) {
4080
+ yield value;
4081
+ }
4082
+ }
4083
+ if (this['for']) {
4084
+ const { value } = this['for'];
4085
+ if (isValueToken(value)) {
4086
+ yield value;
4087
+ }
4088
+ }
4089
+ }
3625
4090
  }
3626
4091
  /**
3627
4092
  * @return null for "none",
@@ -3678,7 +4143,7 @@ class IncludeTag extends Tag {
3678
4143
  }
3679
4144
  else
3680
4145
  tokenizer.p = begin;
3681
- this.hash = new Hash(tokenizer.remaining(), liquid.options.jekyllInclude || liquid.options.keyValueSeparator);
4146
+ this.hash = new Hash(tokenizer, liquid.options.jekyllInclude || liquid.options.keyValueSeparator);
3682
4147
  }
3683
4148
  *render(ctx, emitter) {
3684
4149
  const { liquid, hash, withVar } = this;
@@ -3697,12 +4162,43 @@ class IncludeTag extends Tag {
3697
4162
  ctx.pop();
3698
4163
  ctx.restoreRegister(saved);
3699
4164
  }
4165
+ *children(partials, sync) {
4166
+ if (partials && isString(this['file'])) {
4167
+ return (yield this.liquid._parsePartialFile(this['file'], sync, this['currentFile']));
4168
+ }
4169
+ return [];
4170
+ }
4171
+ partialScope() {
4172
+ if (isString(this['file'])) {
4173
+ let names;
4174
+ if (this.liquid.options.jekyllInclude) {
4175
+ names = ['include'];
4176
+ }
4177
+ else {
4178
+ names = Object.keys(this.hash.hash);
4179
+ if (this.withVar) {
4180
+ names.push([this['file'], this.withVar]);
4181
+ }
4182
+ }
4183
+ return { name: this['file'], isolated: false, scope: names };
4184
+ }
4185
+ }
4186
+ *arguments() {
4187
+ yield* Object.values(this.hash.hash).filter(isValueToken);
4188
+ if (isValueToken(this['file'])) {
4189
+ yield this['file'];
4190
+ }
4191
+ if (isValueToken(this.withVar)) {
4192
+ yield this.withVar;
4193
+ }
4194
+ }
3700
4195
  }
3701
4196
 
3702
4197
  class DecrementTag extends Tag {
3703
4198
  constructor(token, remainTokens, liquid) {
3704
4199
  super(token, remainTokens, liquid);
3705
- this.variable = this.tokenizer.readIdentifier().content;
4200
+ this.identifier = this.tokenizer.readIdentifier();
4201
+ this.variable = this.identifier.content;
3706
4202
  }
3707
4203
  render(context, emitter) {
3708
4204
  const scope = context.environments;
@@ -3711,6 +4207,9 @@ class DecrementTag extends Tag {
3711
4207
  }
3712
4208
  emitter.write(stringify(--scope[this.variable]));
3713
4209
  }
4210
+ *localScope() {
4211
+ yield this.identifier;
4212
+ }
3714
4213
  }
3715
4214
 
3716
4215
  class CycleTag extends Tag {
@@ -3748,6 +4247,12 @@ class CycleTag extends Tag {
3748
4247
  groups[fingerprint] = idx;
3749
4248
  return yield evalToken(candidate, ctx);
3750
4249
  }
4250
+ *arguments() {
4251
+ yield* this.candidates;
4252
+ if (this.group) {
4253
+ yield this.group;
4254
+ }
4255
+ }
3751
4256
  }
3752
4257
 
3753
4258
  class IfTag extends Tag {
@@ -3757,13 +4262,13 @@ class IfTag extends Tag {
3757
4262
  let p = [];
3758
4263
  parser.parseStream(remainTokens)
3759
4264
  .on('start', () => this.branches.push({
3760
- value: new Value(tagToken.args, this.liquid),
4265
+ value: new Value(tagToken.tokenizer.readFilteredValue(), this.liquid),
3761
4266
  templates: (p = [])
3762
4267
  }))
3763
4268
  .on('tag:elsif', (token) => {
3764
4269
  assert(!this.elseTemplates, 'unexpected elsif after else');
3765
4270
  this.branches.push({
3766
- value: new Value(token.args, this.liquid),
4271
+ value: new Value(token.tokenizer.readFilteredValue(), this.liquid),
3767
4272
  templates: (p = [])
3768
4273
  });
3769
4274
  })
@@ -3788,12 +4293,23 @@ class IfTag extends Tag {
3788
4293
  }
3789
4294
  yield r.renderTemplates(this.elseTemplates || [], ctx, emitter);
3790
4295
  }
4296
+ *children() {
4297
+ const templates = this.branches.flatMap(b => b.templates);
4298
+ if (this.elseTemplates) {
4299
+ templates.push(...this.elseTemplates);
4300
+ }
4301
+ return templates;
4302
+ }
4303
+ arguments() {
4304
+ return this.branches.map(b => b.value);
4305
+ }
3791
4306
  }
3792
4307
 
3793
4308
  class IncrementTag extends Tag {
3794
4309
  constructor(token, remainTokens, liquid) {
3795
4310
  super(token, remainTokens, liquid);
3796
- this.variable = this.tokenizer.readIdentifier().content;
4311
+ this.identifier = this.tokenizer.readIdentifier();
4312
+ this.variable = this.identifier.content;
3797
4313
  }
3798
4314
  render(context, emitter) {
3799
4315
  const scope = context.environments;
@@ -3804,6 +4320,9 @@ class IncrementTag extends Tag {
3804
4320
  scope[this.variable]++;
3805
4321
  emitter.write(stringify(val));
3806
4322
  }
4323
+ *localScope() {
4324
+ yield this.identifier;
4325
+ }
3807
4326
  }
3808
4327
 
3809
4328
  class LayoutTag extends Tag {
@@ -3811,7 +4330,7 @@ class LayoutTag extends Tag {
3811
4330
  super(token, remainTokens, liquid);
3812
4331
  this.file = parseFilePath(this.tokenizer, this.liquid, parser);
3813
4332
  this['currentFile'] = token.file;
3814
- this.args = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
4333
+ this.args = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
3815
4334
  this.templates = parser.parseTokens(remainTokens);
3816
4335
  }
3817
4336
  *render(ctx, emitter) {
@@ -3838,6 +4357,28 @@ class LayoutTag extends Tag {
3838
4357
  yield renderer.renderTemplates(templates, ctx, emitter);
3839
4358
  ctx.pop();
3840
4359
  }
4360
+ *children(partials) {
4361
+ const templates = this.templates.slice();
4362
+ if (partials && isString(this.file)) {
4363
+ templates.push(...(yield this.liquid._parsePartialFile(this.file, true, this['currentFile'])));
4364
+ }
4365
+ return templates;
4366
+ }
4367
+ *arguments() {
4368
+ for (const v of Object.values(this.args.hash)) {
4369
+ if (isValueToken(v)) {
4370
+ yield v;
4371
+ }
4372
+ }
4373
+ if (isValueToken(this.file)) {
4374
+ yield this.file;
4375
+ }
4376
+ }
4377
+ partialScope() {
4378
+ if (isString(this.file)) {
4379
+ return { name: this.file, isolated: false, scope: Object.keys(this.args.hash) };
4380
+ }
4381
+ }
3841
4382
  }
3842
4383
 
3843
4384
  class BlockTag extends Tag {
@@ -3877,6 +4418,12 @@ class BlockTag extends Tag {
3877
4418
  ? (superBlock, emitter) => renderChild(new BlockDrop(() => renderCurrent(superBlock, emitter)), emitter)
3878
4419
  : renderCurrent;
3879
4420
  }
4421
+ *children() {
4422
+ return this.templates;
4423
+ }
4424
+ blockScope() {
4425
+ return ['block'];
4426
+ }
3880
4427
  }
3881
4428
 
3882
4429
  class RawTag extends Tag {
@@ -3931,7 +4478,7 @@ class TablerowTag extends Tag {
3931
4478
  }
3932
4479
  this.variable = variable.content;
3933
4480
  this.collection = collectionToken;
3934
- this.args = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
4481
+ this.args = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
3935
4482
  this.templates = [];
3936
4483
  let p;
3937
4484
  const stream = parser.parseStream(remainTokens)
@@ -3969,6 +4516,20 @@ class TablerowTag extends Tag {
3969
4516
  emitter.write('</tr>');
3970
4517
  ctx.pop();
3971
4518
  }
4519
+ *children() {
4520
+ return this.templates;
4521
+ }
4522
+ *arguments() {
4523
+ yield this.collection;
4524
+ for (const v of Object.values(this.args.hash)) {
4525
+ if (isValueToken(v)) {
4526
+ yield v;
4527
+ }
4528
+ }
4529
+ }
4530
+ blockScope() {
4531
+ return [this.variable, 'tablerowloop'];
4532
+ }
3972
4533
  }
3973
4534
 
3974
4535
  class UnlessTag extends Tag {
@@ -3980,7 +4541,7 @@ class UnlessTag extends Tag {
3980
4541
  let elseCount = 0;
3981
4542
  parser.parseStream(remainTokens)
3982
4543
  .on('start', () => this.branches.push({
3983
- value: new Value(tagToken.args, this.liquid),
4544
+ value: new Value(tagToken.tokenizer.readFilteredValue(), this.liquid),
3984
4545
  test: isFalsy,
3985
4546
  templates: (p = [])
3986
4547
  }))
@@ -3990,7 +4551,7 @@ class UnlessTag extends Tag {
3990
4551
  return;
3991
4552
  }
3992
4553
  this.branches.push({
3993
- value: new Value(token.args, this.liquid),
4554
+ value: new Value(token.tokenizer.readFilteredValue(), this.liquid),
3994
4555
  test: isTruthy,
3995
4556
  templates: (p = [])
3996
4557
  });
@@ -4019,17 +4580,27 @@ class UnlessTag extends Tag {
4019
4580
  }
4020
4581
  yield r.renderTemplates(this.elseTemplates, ctx, emitter);
4021
4582
  }
4583
+ *children() {
4584
+ const children = this.branches.flatMap(b => b.templates);
4585
+ if (this.elseTemplates) {
4586
+ children.push(...this.elseTemplates);
4587
+ }
4588
+ return children;
4589
+ }
4590
+ arguments() {
4591
+ return this.branches.map(b => b.value);
4592
+ }
4022
4593
  }
4023
4594
 
4024
4595
  class BreakTag extends Tag {
4025
- render(ctx, emitter) {
4026
- emitter['break'] = true;
4596
+ render(ctx, _emitter) {
4597
+ ctx.breakCalled = true;
4027
4598
  }
4028
4599
  }
4029
4600
 
4030
4601
  class ContinueTag extends Tag {
4031
- render(ctx, emitter) {
4032
- emitter['continue'] = true;
4602
+ render(ctx, _emitter) {
4603
+ ctx.continueCalled = true;
4033
4604
  }
4034
4605
  }
4035
4606
 
@@ -4047,6 +4618,11 @@ class EchoTag extends Tag {
4047
4618
  const val = yield this.value.value(ctx, false);
4048
4619
  emitter.write(val);
4049
4620
  }
4621
+ *arguments() {
4622
+ if (this.value) {
4623
+ yield this.value;
4624
+ }
4625
+ }
4050
4626
  }
4051
4627
 
4052
4628
  class LiquidTag extends Tag {
@@ -4058,6 +4634,9 @@ class LiquidTag extends Tag {
4058
4634
  *render(ctx, emitter) {
4059
4635
  yield this.liquid.renderer.renderTemplates(this.templates, ctx, emitter);
4060
4636
  }
4637
+ *children() {
4638
+ return this.templates;
4639
+ }
4061
4640
  }
4062
4641
 
4063
4642
  class InlineCommentTag extends Tag {
@@ -4208,9 +4787,97 @@ class Liquid {
4208
4787
  self.renderFile(filePath, ctx).then(html => callback(null, html), callback);
4209
4788
  };
4210
4789
  }
4790
+ analyze(template, options = {}) {
4791
+ return __awaiter(this, void 0, void 0, function* () {
4792
+ return analyze(template, options);
4793
+ });
4794
+ }
4795
+ analyzeSync(template, options = {}) {
4796
+ return analyzeSync(template, options);
4797
+ }
4798
+ parseAndAnalyze(html, filename, options = {}) {
4799
+ return __awaiter(this, void 0, void 0, function* () {
4800
+ return analyze(this.parse(html, filename), options);
4801
+ });
4802
+ }
4803
+ parseAndAnalyzeSync(html, filename, options = {}) {
4804
+ return analyzeSync(this.parse(html, filename), options);
4805
+ }
4806
+ /** Return an array of all variables without their properties. */
4807
+ variables(template, options = {}) {
4808
+ return __awaiter(this, void 0, void 0, function* () {
4809
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4810
+ return Object.keys(analysis.variables);
4811
+ });
4812
+ }
4813
+ /** Return an array of all variables without their properties. */
4814
+ variablesSync(template, options = {}) {
4815
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4816
+ return Object.keys(analysis.variables);
4817
+ }
4818
+ /** Return an array of all variables including their properties/paths. */
4819
+ fullVariables(template, options = {}) {
4820
+ return __awaiter(this, void 0, void 0, function* () {
4821
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4822
+ return Array.from(new Set(Object.values(analysis.variables).flatMap((a) => a.map((v) => String(v)))));
4823
+ });
4824
+ }
4825
+ /** Return an array of all variables including their properties/paths. */
4826
+ fullVariablesSync(template, options = {}) {
4827
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4828
+ return Array.from(new Set(Object.values(analysis.variables).flatMap((a) => a.map((v) => String(v)))));
4829
+ }
4830
+ /** Return an array of all variables, each as an array of properties/segments. */
4831
+ variableSegments(template, options = {}) {
4832
+ return __awaiter(this, void 0, void 0, function* () {
4833
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4834
+ return Array.from(strictUniq(Object.values(analysis.variables).flatMap((a) => a.map((v) => v.toArray()))));
4835
+ });
4836
+ }
4837
+ /** Return an array of all variables, each as an array of properties/segments. */
4838
+ variableSegmentsSync(template, options = {}) {
4839
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4840
+ return Array.from(strictUniq(Object.values(analysis.variables).flatMap((a) => a.map((v) => v.toArray()))));
4841
+ }
4842
+ /** Return an array of all expected context variables without their properties. */
4843
+ globalVariables(template, options = {}) {
4844
+ return __awaiter(this, void 0, void 0, function* () {
4845
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4846
+ return Object.keys(analysis.globals);
4847
+ });
4848
+ }
4849
+ /** Return an array of all expected context variables without their properties. */
4850
+ globalVariablesSync(template, options = {}) {
4851
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4852
+ return Object.keys(analysis.globals);
4853
+ }
4854
+ /** Return an array of all expected context variables including their properties/paths. */
4855
+ globalFullVariables(template, options = {}) {
4856
+ return __awaiter(this, void 0, void 0, function* () {
4857
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4858
+ return Array.from(new Set(Object.values(analysis.globals).flatMap((a) => a.map((v) => String(v)))));
4859
+ });
4860
+ }
4861
+ /** Return an array of all expected context variables including their properties/paths. */
4862
+ globalFullVariablesSync(template, options = {}) {
4863
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4864
+ return Array.from(new Set(Object.values(analysis.globals).flatMap((a) => a.map((v) => String(v)))));
4865
+ }
4866
+ /** Return an array of all expected context variables, each as an array of properties/segments. */
4867
+ globalVariableSegments(template, options = {}) {
4868
+ return __awaiter(this, void 0, void 0, function* () {
4869
+ const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
4870
+ return Array.from(strictUniq(Object.values(analysis.globals).flatMap((a) => a.map((v) => v.toArray()))));
4871
+ });
4872
+ }
4873
+ /** Return an array of all expected context variables, each as an array of properties/segments. */
4874
+ globalVariableSegmentsSync(template, options = {}) {
4875
+ const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
4876
+ return Array.from(strictUniq(Object.values(analysis.globals).flatMap((a) => a.map((v) => v.toArray()))));
4877
+ }
4211
4878
  }
4212
4879
 
4213
4880
  /* istanbul ignore file */
4214
4881
  const version = '[VI]{version}[/VI]';
4215
4882
 
4216
- 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 };
4883
+ 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 };