@skeptools/skep-organization-project 0.0.15 → 0.0.16

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 (57) hide show
  1. package/.jsii +113 -3
  2. package/API.md +74 -43
  3. package/lib/skep-organization-project.js +1 -1
  4. package/node_modules/liquidjs/README.md +17 -10
  5. package/node_modules/liquidjs/dist/context/context.d.ts +7 -1
  6. package/node_modules/liquidjs/dist/drop/drop.d.ts +1 -1
  7. package/node_modules/liquidjs/dist/filters/array.d.ts +14 -14
  8. package/node_modules/liquidjs/dist/filters/html.d.ts +6 -5
  9. package/node_modules/liquidjs/dist/filters/math.d.ts +9 -9
  10. package/node_modules/liquidjs/dist/filters/string.d.ts +22 -21
  11. package/node_modules/liquidjs/dist/fs/map-fs.d.ts +13 -0
  12. package/node_modules/liquidjs/dist/fs/node-require.d.ts +1 -2
  13. package/node_modules/liquidjs/dist/index.d.ts +1 -1
  14. package/node_modules/liquidjs/dist/liquid-options.d.ts +28 -2
  15. package/node_modules/liquidjs/dist/liquid.browser.min.js +1 -1
  16. package/node_modules/liquidjs/dist/liquid.browser.min.js.map +1 -1
  17. package/node_modules/liquidjs/dist/{liquid.browser.esm.js → liquid.browser.mjs} +443 -227
  18. package/node_modules/liquidjs/dist/liquid.browser.umd.js +604 -368
  19. package/node_modules/liquidjs/dist/liquid.browser.umd.js.map +1 -1
  20. package/node_modules/liquidjs/dist/liquid.d.ts +3 -0
  21. package/node_modules/liquidjs/dist/{liquid.node.cjs.js → liquid.node.js} +432 -227
  22. package/node_modules/liquidjs/dist/{liquid.node.esm.js → liquid.node.mjs} +448 -228
  23. package/node_modules/liquidjs/dist/parser/parser.d.ts +1 -0
  24. package/node_modules/liquidjs/dist/parser/parser.spec.d.ts +1 -0
  25. package/node_modules/liquidjs/dist/parser/tokenizer.d.ts +4 -3
  26. package/node_modules/liquidjs/dist/tags/block.d.ts +2 -1
  27. package/node_modules/liquidjs/dist/tags/capture.d.ts +2 -1
  28. package/node_modules/liquidjs/dist/tags/case.d.ts +2 -1
  29. package/node_modules/liquidjs/dist/tags/for.d.ts +2 -1
  30. package/node_modules/liquidjs/dist/tags/if.d.ts +3 -2
  31. package/node_modules/liquidjs/dist/tags/include.d.ts +2 -1
  32. package/node_modules/liquidjs/dist/tags/layout.d.ts +2 -1
  33. package/node_modules/liquidjs/dist/tags/liquid.d.ts +2 -1
  34. package/node_modules/liquidjs/dist/tags/render.d.ts +3 -2
  35. package/node_modules/liquidjs/dist/tags/tablerow.d.ts +2 -1
  36. package/node_modules/liquidjs/dist/tags/unless.d.ts +2 -1
  37. package/node_modules/liquidjs/dist/template/filter-impl-options.d.ts +2 -0
  38. package/node_modules/liquidjs/dist/template/filter.d.ts +3 -1
  39. package/node_modules/liquidjs/dist/template/hash.d.ts +1 -1
  40. package/node_modules/liquidjs/dist/template/tag.d.ts +2 -2
  41. package/node_modules/liquidjs/dist/tokens/identifier-token.d.ts +0 -1
  42. package/node_modules/liquidjs/dist/util/assert.d.ts +1 -0
  43. package/node_modules/liquidjs/dist/util/error.d.ts +7 -2
  44. package/node_modules/liquidjs/dist/util/error.spec.d.ts +1 -0
  45. package/node_modules/liquidjs/dist/util/index.d.ts +2 -1
  46. package/node_modules/liquidjs/dist/util/intl.d.ts +6 -0
  47. package/node_modules/liquidjs/dist/util/limiter.d.ts +8 -0
  48. package/node_modules/liquidjs/dist/util/liquid-date.d.ts +39 -7
  49. package/node_modules/liquidjs/dist/util/liquid-date.spec.d.ts +1 -0
  50. package/node_modules/liquidjs/dist/util/performance.d.ts +5 -0
  51. package/node_modules/liquidjs/dist/util/performance.spec.d.ts +1 -0
  52. package/node_modules/liquidjs/dist/util/type-guards.spec.d.ts +1 -0
  53. package/node_modules/liquidjs/dist/util/underscore.d.ts +2 -1
  54. package/node_modules/liquidjs/package.json +10 -7
  55. package/package.json +16 -12
  56. package/node_modules/liquidjs/dist/util/timezone-date.d.ts +0 -44
  57. /package/node_modules/liquidjs/dist/{util/timezone-date.spec.d.ts → fs/map-fs.spec.d.ts} +0 -0
@@ -1,11 +1,12 @@
1
1
  /*
2
- * liquidjs@10.13.0, https://github.com/harttle/liquidjs
2
+ * liquidjs@10.18.0, https://github.com/harttle/liquidjs
3
3
  * (c) 2016-2024 harttle
4
4
  * Released under the MIT License.
5
5
  */
6
6
  import { PassThrough } from 'stream';
7
7
  import { sep, extname, resolve as resolve$1, dirname as dirname$1 } from 'path';
8
8
  import { statSync, readFileSync as readFileSync$1, stat, readFile as readFile$1 } from 'fs';
9
+ import { createRequire } from 'module';
9
10
 
10
11
  class Token {
11
12
  constructor(kind, input, begin, end, file) {
@@ -102,6 +103,10 @@ function toArray(val) {
102
103
  function toValue(value) {
103
104
  return (value instanceof Drop && isFunction(value.valueOf)) ? value.valueOf() : value;
104
105
  }
106
+ function toNumber(value) {
107
+ value = Number(value);
108
+ return isNaN(value) ? 0 : value;
109
+ }
105
110
  function isNumber(value) {
106
111
  return typeof value === 'number';
107
112
  }
@@ -201,14 +206,14 @@ function caseInsensitiveCompare(a, b) {
201
206
  return 0;
202
207
  }
203
208
  function argumentsToValue(fn) {
204
- return (...args) => fn(...args.map(toValue));
209
+ return function (...args) { return fn.call(this, ...args.map(toValue)); };
205
210
  }
206
211
  function escapeRegExp(text) {
207
212
  return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
208
213
  }
209
214
 
210
215
  /**
211
- * targeting ES5, extends Error won't create a proper prototype chain, need a trait to kee track of classes
216
+ * targeting ES5, extends Error won't create a proper prototype chain, need a trait to keep track of classes
212
217
  */
213
218
  const TRAIT = '__liquidClass__';
214
219
  class LiquidError extends Error {
@@ -262,6 +267,19 @@ class RenderError extends LiquidError {
262
267
  return obj.name === 'RenderError';
263
268
  }
264
269
  }
270
+ class LiquidErrors extends LiquidError {
271
+ constructor(errors) {
272
+ super(errors[0], errors[0].token);
273
+ this.errors = errors;
274
+ this.name = 'LiquidErrors';
275
+ const s = errors.length > 1 ? 's' : '';
276
+ this.message = `${errors.length} error${s} found`;
277
+ super.update();
278
+ }
279
+ static is(obj) {
280
+ return obj.name === 'LiquidErrors';
281
+ }
282
+ }
265
283
  class UndefinedVariableError extends LiquidError {
266
284
  constructor(err, token) {
267
285
  super(err, token);
@@ -340,6 +358,9 @@ function assert(predicate, message) {
340
358
  : (message || `expect ${predicate} to be true`);
341
359
  throw new AssertionError(msg);
342
360
  }
361
+ }
362
+ function assertEmpty(predicate, message = `unexpected ${JSON.stringify(predicate)}`) {
363
+ assert(!predicate, message);
343
364
  }
344
365
 
345
366
  class NullDrop extends Drop {
@@ -453,7 +474,12 @@ class BlockDrop extends Drop {
453
474
  }
454
475
 
455
476
  function isComparable(arg) {
456
- return arg && isFunction(arg.equals);
477
+ return (arg &&
478
+ isFunction(arg.equals) &&
479
+ isFunction(arg.gt) &&
480
+ isFunction(arg.geq) &&
481
+ isFunction(arg.lt) &&
482
+ isFunction(arg.leq));
457
483
  }
458
484
 
459
485
  const nil = new NullDrop();
@@ -573,18 +599,6 @@ function toValueSync(val) {
573
599
  }
574
600
 
575
601
  const rFormat = /%([-_0^#:]+)?(\d+)?([EO])?(.)/;
576
- const monthNames = [
577
- 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
578
- 'September', 'October', 'November', 'December'
579
- ];
580
- const dayNames = [
581
- 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
582
- ];
583
- const monthNamesShort = monthNames.map(abbr);
584
- const dayNamesShort = dayNames.map(abbr);
585
- function abbr(str) {
586
- return str.slice(0, 3);
587
- }
588
602
  // prototype extensions
589
603
  function daysInMonth(d) {
590
604
  const feb = isLeapYear(d) ? 29 : 28;
@@ -639,19 +653,7 @@ const padWidths = {
639
653
  U: 2,
640
654
  W: 2
641
655
  };
642
- // default to '0'
643
- const padChars = {
644
- a: ' ',
645
- A: ' ',
646
- b: ' ',
647
- B: ' ',
648
- c: ' ',
649
- e: ' ',
650
- k: ' ',
651
- l: ' ',
652
- p: ' ',
653
- P: ' '
654
- };
656
+ const padSpaceChars = new Set('aAbBceklpP');
655
657
  function getTimezoneOffset(d, opts) {
656
658
  const nOffset = Math.abs(d.getTimezoneOffset());
657
659
  const h = Math.floor(nOffset / 60);
@@ -662,10 +664,10 @@ function getTimezoneOffset(d, opts) {
662
664
  padStart(m, 2, '0');
663
665
  }
664
666
  const formatCodes = {
665
- a: (d) => dayNamesShort[d.getDay()],
666
- A: (d) => dayNames[d.getDay()],
667
- b: (d) => monthNamesShort[d.getMonth()],
668
- B: (d) => monthNames[d.getMonth()],
667
+ a: (d) => d.getShortWeekdayName(),
668
+ A: (d) => d.getLongWeekdayName(),
669
+ b: (d) => d.getShortMonthName(),
670
+ B: (d) => d.getLongMonthName(),
669
671
  c: (d) => d.toLocaleString(),
670
672
  C: (d) => century(d),
671
673
  d: (d) => d.getDate(),
@@ -697,12 +699,7 @@ const formatCodes = {
697
699
  y: (d) => d.getFullYear().toString().slice(2, 4),
698
700
  Y: (d) => d.getFullYear(),
699
701
  z: getTimezoneOffset,
700
- Z: (d, opts) => {
701
- if (d.getTimezoneName) {
702
- return d.getTimezoneName() || getTimezoneOffset(d, opts);
703
- }
704
- return (typeof Intl !== 'undefined' ? Intl.DateTimeFormat().resolvedOptions().timeZone : '');
705
- },
702
+ Z: (d, opts) => d.getTimeZoneName() || getTimezoneOffset(d, opts),
706
703
  't': () => '\t',
707
704
  'n': () => '\n',
708
705
  '%': () => '%'
@@ -728,7 +725,7 @@ function format(d, match) {
728
725
  for (const flag of flagStr)
729
726
  flags[flag] = true;
730
727
  let ret = String(convert(d, { flags, width, modifier }));
731
- let padChar = padChars[conversion] || '0';
728
+ let padChar = padSpaceChars.has(conversion) ? ' ' : '0';
732
729
  let padWidth = width || padWidths[conversion] || 0;
733
730
  if (flags['^'])
734
731
  ret = ret.toUpperCase();
@@ -743,9 +740,22 @@ function format(d, match) {
743
740
  return padStart(ret, padWidth, padChar);
744
741
  }
745
742
 
743
+ function getDateTimeFormat() {
744
+ return (typeof Intl !== 'undefined' ? Intl.DateTimeFormat : undefined);
745
+ }
746
+
746
747
  // one minute in milliseconds
747
748
  const OneMinute = 60000;
748
749
  const ISO8601_TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):(\d{2}))$/;
750
+ const monthNames = [
751
+ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
752
+ 'September', 'October', 'November', 'December'
753
+ ];
754
+ const monthNamesShort = monthNames.map(name => name.slice(0, 3));
755
+ const dayNames = [
756
+ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
757
+ ];
758
+ const dayNamesShort = dayNames.map(name => name.slice(0, 3));
749
759
  /**
750
760
  * A date implementation with timezone info, just like Ruby date
751
761
  *
@@ -753,12 +763,16 @@ const ISO8601_TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):(\d{2}))$/;
753
763
  * - create a Date offset by it's timezone difference, avoiding overriding a bunch of methods
754
764
  * - rewrite getTimezoneOffset() to trick strftime
755
765
  */
756
- class TimezoneDate {
757
- constructor(init, timezone) {
758
- this.date = init instanceof TimezoneDate
759
- ? init.date
760
- : new Date(init);
761
- this.timezoneOffset = isString(timezone) ? TimezoneDate.getTimezoneOffset(timezone, this.date) : timezone;
766
+ class LiquidDate {
767
+ constructor(init, locale, timezone) {
768
+ this.locale = locale;
769
+ this.DateTimeFormat = getDateTimeFormat();
770
+ this.date = new Date(init);
771
+ this.timezoneFixed = timezone !== undefined;
772
+ if (timezone === undefined) {
773
+ timezone = this.date.getTimezoneOffset();
774
+ }
775
+ this.timezoneOffset = isString(timezone) ? LiquidDate.getTimezoneOffset(timezone, this.date) : timezone;
762
776
  this.timezoneName = isString(timezone) ? timezone : '';
763
777
  const diff = (this.date.getTimezoneOffset() - this.timezoneOffset) * OneMinute;
764
778
  const time = this.date.getTime() + diff;
@@ -806,8 +820,34 @@ class TimezoneDate {
806
820
  getTimezoneOffset() {
807
821
  return this.timezoneOffset;
808
822
  }
809
- getTimezoneName() {
810
- return this.timezoneName;
823
+ getTimeZoneName() {
824
+ if (this.timezoneFixed)
825
+ return this.timezoneName;
826
+ if (!this.DateTimeFormat)
827
+ return;
828
+ return this.DateTimeFormat().resolvedOptions().timeZone;
829
+ }
830
+ getLongMonthName() {
831
+ var _a;
832
+ return (_a = this.format({ month: 'long' })) !== null && _a !== void 0 ? _a : monthNames[this.getMonth()];
833
+ }
834
+ getShortMonthName() {
835
+ var _a;
836
+ return (_a = this.format({ month: 'short' })) !== null && _a !== void 0 ? _a : monthNamesShort[this.getMonth()];
837
+ }
838
+ getLongWeekdayName() {
839
+ var _a;
840
+ return (_a = this.format({ weekday: 'long' })) !== null && _a !== void 0 ? _a : dayNames[this.displayDate.getDay()];
841
+ }
842
+ getShortWeekdayName() {
843
+ var _a;
844
+ return (_a = this.format({ weekday: 'short' })) !== null && _a !== void 0 ? _a : dayNamesShort[this.displayDate.getDay()];
845
+ }
846
+ valid() {
847
+ return !isNaN(this.getTime());
848
+ }
849
+ format(options) {
850
+ return this.DateTimeFormat && this.DateTimeFormat(this.locale, options).format(this.displayDate);
811
851
  }
812
852
  /**
813
853
  * Create a Date object fixed to it's declared Timezone. Both
@@ -822,21 +862,21 @@ class TimezoneDate {
822
862
  * we create a different Date to trick strftime, it's both simpler and more performant.
823
863
  * Given that a template is expected to be parsed fewer times than rendered.
824
864
  */
825
- static createDateFixedToTimezone(dateString) {
865
+ static createDateFixedToTimezone(dateString, locale) {
826
866
  const m = dateString.match(ISO8601_TIMEZONE_PATTERN);
827
867
  // representing a UTC timestamp
828
868
  if (m && m[1] === 'Z') {
829
- return new TimezoneDate(+new Date(dateString), 0);
869
+ return new LiquidDate(+new Date(dateString), locale, 0);
830
870
  }
831
871
  // has a timezone specified
832
872
  if (m && m[2] && m[3] && m[4]) {
833
873
  const [, , sign, hours, minutes] = m;
834
874
  const offset = (sign === '+' ? -1 : 1) * (parseInt(hours, 10) * 60 + parseInt(minutes, 10));
835
- return new TimezoneDate(+new Date(dateString), offset);
875
+ return new LiquidDate(+new Date(dateString), locale, offset);
836
876
  }
837
- return new Date(dateString);
877
+ return new LiquidDate(dateString, locale);
838
878
  }
839
- static getTimezoneOffset(timezoneName, date = new Date()) {
879
+ static getTimezoneOffset(timezoneName, date) {
840
880
  const localDateString = date.toLocaleString('en-US', { timeZone: timezoneName });
841
881
  const utcDateString = date.toLocaleString('en-US', { timeZone: 'UTC' });
842
882
  const localDate = new Date(localDateString);
@@ -845,6 +885,23 @@ class TimezoneDate {
845
885
  }
846
886
  }
847
887
 
888
+ class Limiter {
889
+ constructor(resource, limit) {
890
+ this.base = 0;
891
+ this.message = `${resource} limit exceeded`;
892
+ this.limit = limit;
893
+ }
894
+ use(count) {
895
+ count = toNumber(count);
896
+ assert(this.base + count <= this.limit, this.message);
897
+ this.base += count;
898
+ }
899
+ check(count) {
900
+ count = toNumber(count);
901
+ assert(count <= this.limit, this.message);
902
+ }
903
+ }
904
+
848
905
  class DelimitedToken extends Token {
849
906
  constructor(kind, [contentBegin, contentEnd], input, begin, end, trimLeft, trimRight, file) {
850
907
  super(kind, input, begin, end, file);
@@ -925,16 +982,6 @@ class IdentifierToken extends Token {
925
982
  this.file = file;
926
983
  this.content = this.getText();
927
984
  }
928
- isNumber(allowSign = false) {
929
- const begin = allowSign && TYPES[this.input.charCodeAt(this.begin)] & SIGN
930
- ? this.begin + 1
931
- : this.begin;
932
- for (let i = begin; i < this.end; i++) {
933
- if (!(TYPES[this.input.charCodeAt(i)] & NUMBER))
934
- return false;
935
- }
936
- return true;
937
- }
938
985
  }
939
986
 
940
987
  class LiteralToken extends Token {
@@ -1123,6 +1170,15 @@ class FilteredValueToken extends Token {
1123
1170
  }
1124
1171
  }
1125
1172
 
1173
+ const polyfill = {
1174
+ now: () => Date.now()
1175
+ };
1176
+ function getPerformance() {
1177
+ return (typeof global === 'object' && global.performance) ||
1178
+ (typeof window === 'object' && window.performance) ||
1179
+ polyfill;
1180
+ }
1181
+
1126
1182
  class SimpleEmitter {
1127
1183
  constructor() {
1128
1184
  this.buffer = '';
@@ -1178,7 +1234,9 @@ class Render {
1178
1234
  if (!emitter) {
1179
1235
  emitter = ctx.opts.keepOutputType ? new KeepingTypeEmitter() : new SimpleEmitter();
1180
1236
  }
1237
+ const errors = [];
1181
1238
  for (const tpl of templates) {
1239
+ ctx.renderLimit.check(getPerformance().now());
1182
1240
  try {
1183
1241
  // if tpl.render supports emitter, it'll return empty `html`
1184
1242
  const html = yield tpl.render(ctx, emitter);
@@ -1188,10 +1246,16 @@ class Render {
1188
1246
  break;
1189
1247
  }
1190
1248
  catch (e) {
1191
- const err = RenderError.is(e) ? e : new RenderError(e, tpl);
1192
- throw err;
1249
+ const err = LiquidError.is(e) ? e : new RenderError(e, tpl);
1250
+ if (ctx.opts.catchAllErrors)
1251
+ errors.push(err);
1252
+ else
1253
+ throw err;
1193
1254
  }
1194
1255
  }
1256
+ if (errors.length) {
1257
+ throw new LiquidErrors(errors);
1258
+ }
1195
1259
  return emitter.buffer;
1196
1260
  }
1197
1261
  }
@@ -1285,6 +1349,7 @@ function isTruthy(val, ctx) {
1285
1349
  return !isFalsy(val, ctx);
1286
1350
  }
1287
1351
  function isFalsy(val, ctx) {
1352
+ val = toValue(val);
1288
1353
  if (ctx.opts.jsTruthy) {
1289
1354
  return !val;
1290
1355
  }
@@ -1412,7 +1477,10 @@ class LRU {
1412
1477
  }
1413
1478
  }
1414
1479
 
1415
- const requireResolve = require.resolve;
1480
+ function requireResolve (file) {
1481
+ const require = createRequire(process.cwd() + '/');
1482
+ return require.resolve(file)
1483
+ }
1416
1484
 
1417
1485
  const statAsync = promisify(stat);
1418
1486
  const readFileAsync = promisify(readFile$1);
@@ -1531,22 +1599,30 @@ const unescapeMap = {
1531
1599
  '&#39;': "'"
1532
1600
  };
1533
1601
  function escape(str) {
1534
- return stringify(str).replace(/&|<|>|"|'/g, m => escapeMap[m]);
1602
+ str = stringify(str);
1603
+ this.context.memoryLimit.use(str.length);
1604
+ return str.replace(/&|<|>|"|'/g, m => escapeMap[m]);
1535
1605
  }
1536
1606
  function xml_escape(str) {
1537
- return escape(str);
1607
+ return escape.call(this, str);
1538
1608
  }
1539
1609
  function unescape(str) {
1540
- return stringify(str).replace(/&(amp|lt|gt|#34|#39);/g, m => unescapeMap[m]);
1610
+ str = stringify(str);
1611
+ this.context.memoryLimit.use(str.length);
1612
+ return str.replace(/&(amp|lt|gt|#34|#39);/g, m => unescapeMap[m]);
1541
1613
  }
1542
1614
  function escape_once(str) {
1543
- return escape(unescape(stringify(str)));
1615
+ return escape.call(this, unescape.call(this, str));
1544
1616
  }
1545
1617
  function newline_to_br(v) {
1546
- return stringify(v).replace(/\r?\n/gm, '<br />\n');
1618
+ const str = stringify(v);
1619
+ this.context.memoryLimit.use(str.length);
1620
+ return str.replace(/\r?\n/gm, '<br />\n');
1547
1621
  }
1548
1622
  function strip_html(v) {
1549
- return stringify(v).replace(/<script[\s\S]*?<\/script>|<style[\s\S]*?<\/style>|<.*?>|<!--[\s\S]*?-->/g, '');
1623
+ const str = stringify(v);
1624
+ this.context.memoryLimit.use(str.length);
1625
+ return str.replace(/<script[\s\S]*?<\/script>|<style[\s\S]*?<\/style>|<.*?>|<!--[\s\S]*?-->/g, '');
1550
1626
  }
1551
1627
 
1552
1628
  var htmlFilters = /*#__PURE__*/Object.freeze({
@@ -1558,18 +1634,68 @@ var htmlFilters = /*#__PURE__*/Object.freeze({
1558
1634
  strip_html: strip_html
1559
1635
  });
1560
1636
 
1637
+ class MapFS {
1638
+ constructor(mapping) {
1639
+ this.mapping = mapping;
1640
+ this.sep = '/';
1641
+ }
1642
+ exists(filepath) {
1643
+ return __awaiter(this, void 0, void 0, function* () {
1644
+ return this.existsSync(filepath);
1645
+ });
1646
+ }
1647
+ existsSync(filepath) {
1648
+ return !isNil(this.mapping[filepath]);
1649
+ }
1650
+ readFile(filepath) {
1651
+ return __awaiter(this, void 0, void 0, function* () {
1652
+ return this.readFileSync(filepath);
1653
+ });
1654
+ }
1655
+ readFileSync(filepath) {
1656
+ const content = this.mapping[filepath];
1657
+ if (isNil(content))
1658
+ throw new Error(`ENOENT: ${filepath}`);
1659
+ return content;
1660
+ }
1661
+ dirname(filepath) {
1662
+ const segments = filepath.split(this.sep);
1663
+ segments.pop();
1664
+ return segments.join(this.sep);
1665
+ }
1666
+ resolve(dir, file, ext) {
1667
+ file += ext;
1668
+ if (dir === '.')
1669
+ return file;
1670
+ const segments = dir.split(/\/+/);
1671
+ for (const segment of file.split(this.sep)) {
1672
+ if (segment === '.' || segment === '')
1673
+ continue;
1674
+ else if (segment === '..') {
1675
+ if (segments.length > 1 || segments[0] !== '')
1676
+ segments.pop();
1677
+ }
1678
+ else
1679
+ segments.push(segment);
1680
+ }
1681
+ return segments.join(this.sep);
1682
+ }
1683
+ }
1684
+
1561
1685
  const defaultOptions = {
1562
1686
  root: ['.'],
1563
1687
  layouts: ['.'],
1564
1688
  partials: ['.'],
1565
1689
  relativeReference: true,
1566
1690
  jekyllInclude: false,
1691
+ keyValueSeparator: ':',
1567
1692
  cache: undefined,
1568
1693
  extname: '',
1569
1694
  fs: fs,
1570
1695
  dynamicPartials: true,
1571
1696
  jsTruthy: false,
1572
1697
  dateFormat: '%A, %B %-e, %Y at %-l:%M %P %z',
1698
+ locale: '',
1573
1699
  trimTagRight: false,
1574
1700
  trimTagLeft: false,
1575
1701
  trimOutputRight: false,
@@ -1586,9 +1712,13 @@ const defaultOptions = {
1586
1712
  lenientIf: false,
1587
1713
  globals: {},
1588
1714
  keepOutputType: false,
1589
- operators: defaultOperators
1715
+ operators: defaultOperators,
1716
+ memoryLimit: Infinity,
1717
+ parseLimit: Infinity,
1718
+ renderLimit: Infinity
1590
1719
  };
1591
1720
  function normalize(options) {
1721
+ var _a, _b;
1592
1722
  if (options.hasOwnProperty('root')) {
1593
1723
  if (!options.hasOwnProperty('partials'))
1594
1724
  options.partials = options.root;
@@ -1614,6 +1744,14 @@ function normalize(options) {
1614
1744
  options.partials = normalizeDirectoryList(options.partials);
1615
1745
  options.layouts = normalizeDirectoryList(options.layouts);
1616
1746
  options.outputEscape = options.outputEscape && getOutputEscapeFunction(options.outputEscape);
1747
+ if (!options.locale) {
1748
+ options.locale = (_b = (_a = getDateTimeFormat()) === null || _a === void 0 ? void 0 : _a().resolvedOptions().locale) !== null && _b !== void 0 ? _b : 'en-US';
1749
+ }
1750
+ if (options.templates) {
1751
+ options.fs = new MapFS(options.templates);
1752
+ options.relativeReference = true;
1753
+ options.root = options.partials = options.layouts = '.';
1754
+ }
1617
1755
  return options;
1618
1756
  }
1619
1757
  function getOutputEscapeFunction(nameOrFunction) {
@@ -1740,9 +1878,7 @@ class Tokenizer {
1740
1878
  this.skipBlank();
1741
1879
  if (this.end())
1742
1880
  return null;
1743
- this.assert(this.peek() === '|', `expected "|" before filter`);
1744
- this.p++;
1745
- const begin = this.p;
1881
+ this.assert(this.read() === '|', `expected "|" before filter`);
1746
1882
  const name = this.readIdentifier();
1747
1883
  if (!name.size()) {
1748
1884
  this.assert(this.end(), `expected filter name`);
@@ -1763,7 +1899,7 @@ class Tokenizer {
1763
1899
  else {
1764
1900
  throw this.error('expected ":" after filter name');
1765
1901
  }
1766
- return new FilterToken(name.getText(), args, this.input, begin, this.p, this.file);
1902
+ return new FilterToken(name.getText(), args, this.input, name.begin, this.p, this.file);
1767
1903
  }
1768
1904
  readFilterArg() {
1769
1905
  const key = this.readValue();
@@ -1804,7 +1940,7 @@ class Tokenizer {
1804
1940
  }
1805
1941
  return new HTMLToken(this.input, begin, this.p, this.file);
1806
1942
  }
1807
- readTagToken(options = defaultOptions) {
1943
+ readTagToken(options) {
1808
1944
  const { file, input } = this;
1809
1945
  const begin = this.p;
1810
1946
  if (this.readToDelimiter(options.tagDelimiterRight) === -1) {
@@ -1935,7 +2071,7 @@ class Tokenizer {
1935
2071
  return;
1936
2072
  let value;
1937
2073
  this.skipBlank();
1938
- const sep = jekyllStyle ? '=' : ':';
2074
+ const sep = isString(jekyllStyle) ? jekyllStyle : (jekyllStyle ? '=' : ':');
1939
2075
  if (this.peek() === sep) {
1940
2076
  ++this.p;
1941
2077
  value = this.readValue();
@@ -1951,6 +2087,9 @@ class Tokenizer {
1951
2087
  end() {
1952
2088
  return this.p >= this.N;
1953
2089
  }
2090
+ read() {
2091
+ return this.input[this.p++];
2092
+ }
1954
2093
  readTo(end) {
1955
2094
  while (this.p < this.N) {
1956
2095
  ++this.p;
@@ -2199,7 +2338,7 @@ function createTagClass(options) {
2199
2338
  }
2200
2339
  }
2201
2340
  *render(ctx, emitter) {
2202
- const hash = (yield new Hash(this.token.args).render(ctx));
2341
+ const hash = (yield new Hash(this.token.args, ctx.opts.keyValueSeparator).render(ctx));
2203
2342
  return yield options.render.call(this, ctx, emitter, hash);
2204
2343
  }
2205
2344
  };
@@ -2210,13 +2349,14 @@ function isKeyValuePair(arr) {
2210
2349
  }
2211
2350
 
2212
2351
  class Filter {
2213
- constructor(name, options, args, liquid) {
2214
- this.name = name;
2352
+ constructor(token, options, liquid) {
2353
+ this.token = token;
2354
+ this.name = token.name;
2215
2355
  this.handler = isFunction(options)
2216
2356
  ? options
2217
2357
  : (isFunction(options === null || options === void 0 ? void 0 : options.handler) ? options.handler : identify);
2218
2358
  this.raw = !isFunction(options) && !!(options === null || options === void 0 ? void 0 : options.raw);
2219
- this.args = args;
2359
+ this.args = token.args;
2220
2360
  this.liquid = liquid;
2221
2361
  }
2222
2362
  *render(value, context) {
@@ -2227,7 +2367,7 @@ class Filter {
2227
2367
  else
2228
2368
  argv.push(yield evalToken(arg, context));
2229
2369
  }
2230
- return yield this.handler.apply({ context, liquid: this.liquid }, [value, ...argv]);
2370
+ return yield this.handler.apply({ context, token: this.token, liquid: this.liquid }, [value, ...argv]);
2231
2371
  }
2232
2372
  }
2233
2373
 
@@ -2241,7 +2381,7 @@ class Value {
2241
2381
  ? new Tokenizer(input, liquid.options.operators).readFilteredValue()
2242
2382
  : input;
2243
2383
  this.initial = token.initial;
2244
- this.filters = token.filters.map(({ name, args }) => new Filter(name, this.getFilter(liquid, name), args, liquid));
2384
+ this.filters = token.filters.map(token => new Filter(token, this.getFilter(liquid, token.name), liquid));
2245
2385
  }
2246
2386
  *value(ctx, lenient) {
2247
2387
  lenient = lenient || (ctx.opts.lenientIf && this.filters.length > 0 && this.filters[0].name === 'default');
@@ -2267,7 +2407,8 @@ class Output extends TemplateImpl {
2267
2407
  const filters = this.value.filters;
2268
2408
  const outputEscape = liquid.options.outputEscape;
2269
2409
  if (!((_a = filters[filters.length - 1]) === null || _a === void 0 ? void 0 : _a.raw) && outputEscape) {
2270
- filters.push(new Filter(toString.call(outputEscape), outputEscape, [], liquid));
2410
+ const token = new FilterToken(toString.call(outputEscape), [], '', 0, 0);
2411
+ filters.push(new Filter(token, outputEscape, liquid));
2271
2412
  }
2272
2413
  }
2273
2414
  *render(ctx, emitter) {
@@ -2302,7 +2443,7 @@ class Loader {
2302
2443
  this.shouldLoadRelative = (referencedFile) => rRelativePath.test(referencedFile);
2303
2444
  }
2304
2445
  else {
2305
- this.shouldLoadRelative = (referencedFile) => false;
2446
+ this.shouldLoadRelative = (_referencedFile) => false;
2306
2447
  }
2307
2448
  this.contains = this.options.fs.contains || (() => true);
2308
2449
  }
@@ -2359,8 +2500,11 @@ class Parser {
2359
2500
  this.fs = this.liquid.options.fs;
2360
2501
  this.parseFile = this.cache ? this._parseFileCached : this._parseFile;
2361
2502
  this.loader = new Loader(this.liquid.options);
2503
+ this.parseLimit = new Limiter('parse length', liquid.options.parseLimit);
2362
2504
  }
2363
2505
  parse(html, filepath) {
2506
+ html = String(html);
2507
+ this.parseLimit.use(html.length);
2364
2508
  const tokenizer = new Tokenizer(html, this.liquid.options.operators, filepath);
2365
2509
  const tokens = tokenizer.readTopLevelTokens(this.liquid.options);
2366
2510
  return this.parseTokens(tokens);
@@ -2368,9 +2512,20 @@ class Parser {
2368
2512
  parseTokens(tokens) {
2369
2513
  let token;
2370
2514
  const templates = [];
2515
+ const errors = [];
2371
2516
  while ((token = tokens.shift())) {
2372
- templates.push(this.parseToken(token, tokens));
2517
+ try {
2518
+ templates.push(this.parseToken(token, tokens));
2519
+ }
2520
+ catch (err) {
2521
+ if (this.liquid.options.catchAllErrors)
2522
+ errors.push(err);
2523
+ else
2524
+ throw err;
2525
+ }
2373
2526
  }
2527
+ if (errors.length)
2528
+ throw new LiquidErrors(errors);
2374
2529
  return templates;
2375
2530
  }
2376
2531
  parseToken(token, remainTokens) {
@@ -2378,7 +2533,7 @@ class Parser {
2378
2533
  if (isTagToken(token)) {
2379
2534
  const TagClass = this.liquid.tags[token.name];
2380
2535
  assert(TagClass, `tag "${token.name}" not found`);
2381
- return new TagClass(token, remainTokens, this.liquid);
2536
+ return new TagClass(token, remainTokens, this.liquid, this);
2382
2537
  }
2383
2538
  if (isOutputToken(token)) {
2384
2539
  return new Output(token, this.liquid);
@@ -2416,7 +2571,7 @@ class Parser {
2416
2571
  }
2417
2572
  *_parseFile(file, sync, type = LookupType.Root, currentFile) {
2418
2573
  const filepath = yield this.loader.lookup(file, type, sync, currentFile);
2419
- return this.liquid.parse(sync ? this.fs.readFileSync(filepath) : yield this.fs.readFile(filepath), filepath);
2574
+ return this.parse(sync ? this.fs.readFileSync(filepath) : yield this.fs.readFile(filepath), filepath);
2420
2575
  }
2421
2576
  }
2422
2577
 
@@ -2491,8 +2646,8 @@ var typeGuards = /*#__PURE__*/Object.freeze({
2491
2646
  });
2492
2647
 
2493
2648
  class Context {
2494
- constructor(env = {}, opts = defaultOptions, renderOptions = {}) {
2495
- var _a, _b, _c;
2649
+ constructor(env = {}, opts = defaultOptions, renderOptions = {}, { memoryLimit, renderLimit } = {}) {
2650
+ var _a, _b, _c, _d, _e;
2496
2651
  /**
2497
2652
  * insert a Context-level empty scope,
2498
2653
  * for tags like `{% capture %}` `{% assign %}` to operate
@@ -2505,6 +2660,8 @@ class Context {
2505
2660
  this.environments = isObject(env) ? env : Object(env);
2506
2661
  this.strictVariables = (_b = renderOptions.strictVariables) !== null && _b !== void 0 ? _b : this.opts.strictVariables;
2507
2662
  this.ownPropertyOnly = (_c = renderOptions.ownPropertyOnly) !== null && _c !== void 0 ? _c : opts.ownPropertyOnly;
2663
+ this.memoryLimit = memoryLimit !== null && memoryLimit !== void 0 ? memoryLimit : new Limiter('memory alloc', (_d = renderOptions.memoryLimit) !== null && _d !== void 0 ? _d : opts.memoryLimit);
2664
+ this.renderLimit = renderLimit !== null && renderLimit !== void 0 ? renderLimit : new Limiter('template render', getPerformance().now() + ((_e = renderOptions.renderLimit) !== null && _e !== void 0 ? _e : opts.renderLimit));
2508
2665
  }
2509
2666
  getRegister(key) {
2510
2667
  return (this.registers[key] = this.registers[key] || {});
@@ -2561,6 +2718,16 @@ class Context {
2561
2718
  bottom() {
2562
2719
  return this.scopes[0];
2563
2720
  }
2721
+ spawn(scope = {}) {
2722
+ return new Context(scope, this.opts, {
2723
+ sync: this.sync,
2724
+ globals: this.globals,
2725
+ strictVariables: this.strictVariables
2726
+ }, {
2727
+ renderLimit: this.renderLimit,
2728
+ memoryLimit: this.memoryLimit
2729
+ });
2730
+ }
2564
2731
  findScope(key) {
2565
2732
  for (let i = this.scopes.length - 1; i >= 0; i--) {
2566
2733
  const candidate = this.scopes[i];
@@ -2592,7 +2759,7 @@ function readProperty(obj, key, ownPropertyOnly) {
2592
2759
  return value;
2593
2760
  }
2594
2761
  function readJSProperty(obj, key, ownPropertyOnly) {
2595
- if (ownPropertyOnly && !Object.hasOwnProperty.call(obj, key) && !(obj instanceof Drop))
2762
+ if (ownPropertyOnly && !hasOwnProperty.call(obj, key) && !(obj instanceof Drop))
2596
2763
  return undefined;
2597
2764
  return obj[key];
2598
2765
  }
@@ -2607,7 +2774,7 @@ function readLast(obj) {
2607
2774
  return obj['last'];
2608
2775
  }
2609
2776
  function readSize(obj) {
2610
- if (obj.hasOwnProperty('size') || obj['size'] !== undefined)
2777
+ if (hasOwnProperty.call(obj, 'size') || obj['size'] !== undefined)
2611
2778
  return obj['size'];
2612
2779
  if (isArray(obj) || isString(obj))
2613
2780
  return obj.length;
@@ -2714,13 +2881,25 @@ var urlFilters = /*#__PURE__*/Object.freeze({
2714
2881
  slugify: slugify
2715
2882
  });
2716
2883
 
2717
- const join = argumentsToValue((v, arg) => toArray(v).join(arg === undefined ? ' ' : arg));
2884
+ const join = argumentsToValue(function (v, arg) {
2885
+ const array = toArray(v);
2886
+ const sep = isNil(arg) ? ' ' : stringify(arg);
2887
+ const complexity = array.length * (1 + sep.length);
2888
+ this.context.memoryLimit.use(complexity);
2889
+ return array.join(sep);
2890
+ });
2718
2891
  const last$1 = argumentsToValue((v) => isArray(v) ? last(v) : '');
2719
2892
  const first = argumentsToValue((v) => isArray(v) ? v[0] : '');
2720
- const reverse = argumentsToValue((v) => [...toArray(v)].reverse());
2893
+ const reverse = argumentsToValue(function (v) {
2894
+ const array = toArray(v);
2895
+ this.context.memoryLimit.use(array.length);
2896
+ return [...array].reverse();
2897
+ });
2721
2898
  function* sort(arr, property) {
2722
2899
  const values = [];
2723
- for (const item of toArray(arr)) {
2900
+ const array = toArray(arr);
2901
+ this.context.memoryLimit.use(array.length);
2902
+ for (const item of array) {
2724
2903
  values.push([
2725
2904
  item,
2726
2905
  property ? yield this.context._getFromScope(item, stringify(property).split('.'), false) : item
@@ -2737,35 +2916,47 @@ function sort_natural(input, property) {
2737
2916
  const compare = property === undefined
2738
2917
  ? caseInsensitiveCompare
2739
2918
  : (lhs, rhs) => caseInsensitiveCompare(lhs[propertyString], rhs[propertyString]);
2740
- return [...toArray(input)].sort(compare);
2919
+ const array = toArray(input);
2920
+ this.context.memoryLimit.use(array.length);
2921
+ return [...array].sort(compare);
2741
2922
  }
2742
2923
  const size = (v) => (v && v.length) || 0;
2743
2924
  function* map(arr, property) {
2744
2925
  const results = [];
2745
- for (const item of toArray(arr)) {
2926
+ const array = toArray(arr);
2927
+ this.context.memoryLimit.use(array.length);
2928
+ for (const item of array) {
2746
2929
  results.push(yield this.context._getFromScope(item, stringify(property), false));
2747
2930
  }
2748
2931
  return results;
2749
2932
  }
2750
2933
  function* sum(arr, property) {
2751
2934
  let sum = 0;
2752
- for (const item of toArray(arr)) {
2935
+ const array = toArray(arr);
2936
+ for (const item of array) {
2753
2937
  const data = Number(property ? yield this.context._getFromScope(item, stringify(property), false) : item);
2754
2938
  sum += Number.isNaN(data) ? 0 : data;
2755
2939
  }
2756
2940
  return sum;
2757
2941
  }
2758
2942
  function compact(arr) {
2759
- return toArray(arr).filter(x => !isNil(toValue(x)));
2943
+ const array = toArray(arr);
2944
+ this.context.memoryLimit.use(array.length);
2945
+ return array.filter(x => !isNil(toValue(x)));
2760
2946
  }
2761
2947
  function concat(v, arg = []) {
2762
- return toArray(v).concat(toArray(arg));
2948
+ const lhs = toArray(v);
2949
+ const rhs = toArray(arg);
2950
+ this.context.memoryLimit.use(lhs.length + rhs.length);
2951
+ return lhs.concat(rhs);
2763
2952
  }
2764
2953
  function push(v, arg) {
2765
- return concat(v, [arg]);
2954
+ return concat.call(this, v, [arg]);
2766
2955
  }
2767
2956
  function unshift(v, arg) {
2768
- const clone = [...toArray(v)];
2957
+ const array = toArray(v);
2958
+ this.context.memoryLimit.use(array.length);
2959
+ const clone = [...array];
2769
2960
  clone.unshift(arg);
2770
2961
  return clone;
2771
2962
  }
@@ -2775,7 +2966,9 @@ function pop(v) {
2775
2966
  return clone;
2776
2967
  }
2777
2968
  function shift(v) {
2778
- const clone = [...toArray(v)];
2969
+ const array = toArray(v);
2970
+ this.context.memoryLimit.use(array.length);
2971
+ const clone = [...array];
2779
2972
  clone.shift();
2780
2973
  return clone;
2781
2974
  }
@@ -2786,14 +2979,16 @@ function slice(v, begin, length = 1) {
2786
2979
  if (!isArray(v))
2787
2980
  v = stringify(v);
2788
2981
  begin = begin < 0 ? v.length + begin : begin;
2982
+ this.context.memoryLimit.use(length);
2789
2983
  return v.slice(begin, begin + length);
2790
2984
  }
2791
2985
  function* where(arr, property, expected) {
2792
2986
  const values = [];
2793
2987
  arr = toArray(arr);
2988
+ this.context.memoryLimit.use(arr.length);
2794
2989
  const token = new Tokenizer(stringify(property)).readScopeValue();
2795
2990
  for (const item of arr) {
2796
- values.push(yield evalToken(token, new Context(item)));
2991
+ values.push(yield evalToken(token, this.context.spawn(item)));
2797
2992
  }
2798
2993
  return arr.filter((_, i) => {
2799
2994
  if (expected === undefined)
@@ -2804,8 +2999,10 @@ function* where(arr, property, expected) {
2804
2999
  function* where_exp(arr, itemName, exp) {
2805
3000
  const filtered = [];
2806
3001
  const keyTemplate = new Value(stringify(exp), this.liquid);
2807
- for (const item of toArray(arr)) {
2808
- const value = yield keyTemplate.value(new Context({ [itemName]: item }));
3002
+ const array = toArray(arr);
3003
+ this.context.memoryLimit.use(array.length);
3004
+ for (const item of array) {
3005
+ const value = yield keyTemplate.value(this.context.spawn({ [itemName]: item }));
2809
3006
  if (value)
2810
3007
  filtered.push(item);
2811
3008
  }
@@ -2815,8 +3012,9 @@ function* group_by(arr, property) {
2815
3012
  const map = new Map();
2816
3013
  arr = toArray(arr);
2817
3014
  const token = new Tokenizer(stringify(property)).readScopeValue();
3015
+ this.context.memoryLimit.use(arr.length);
2818
3016
  for (const item of arr) {
2819
- const key = yield evalToken(token, new Context(item));
3017
+ const key = yield evalToken(token, this.context.spawn(item));
2820
3018
  if (!map.has(key))
2821
3019
  map.set(key, []);
2822
3020
  map.get(key).push(item);
@@ -2826,8 +3024,10 @@ function* group_by(arr, property) {
2826
3024
  function* group_by_exp(arr, itemName, exp) {
2827
3025
  const map = new Map();
2828
3026
  const keyTemplate = new Value(stringify(exp), this.liquid);
2829
- for (const item of toArray(arr)) {
2830
- const key = yield keyTemplate.value(new Context({ [itemName]: item }));
3027
+ arr = toArray(arr);
3028
+ this.context.memoryLimit.use(arr.length);
3029
+ for (const item of arr) {
3030
+ const key = yield keyTemplate.value(this.context.spawn({ [itemName]: item }));
2831
3031
  if (!map.has(key))
2832
3032
  map.set(key, []);
2833
3033
  map.get(key).push(item);
@@ -2836,31 +3036,26 @@ function* group_by_exp(arr, itemName, exp) {
2836
3036
  }
2837
3037
  function* find(arr, property, expected) {
2838
3038
  const token = new Tokenizer(stringify(property)).readScopeValue();
2839
- for (const item of toArray(arr)) {
2840
- const value = yield evalToken(token, new Context(item));
3039
+ const array = toArray(arr);
3040
+ for (const item of array) {
3041
+ const value = yield evalToken(token, this.context.spawn(item));
2841
3042
  if (equals(value, expected))
2842
3043
  return item;
2843
3044
  }
2844
- return null;
2845
3045
  }
2846
3046
  function* find_exp(arr, itemName, exp) {
2847
3047
  const predicate = new Value(stringify(exp), this.liquid);
2848
- for (const item of toArray(arr)) {
2849
- const value = yield predicate.value(new Context({ [itemName]: item }));
3048
+ const array = toArray(arr);
3049
+ for (const item of array) {
3050
+ const value = yield predicate.value(this.context.spawn({ [itemName]: item }));
2850
3051
  if (value)
2851
3052
  return item;
2852
3053
  }
2853
- return null;
2854
3054
  }
2855
3055
  function uniq(arr) {
2856
- arr = toValue(arr);
2857
- const u = {};
2858
- return (arr || []).filter(val => {
2859
- if (hasOwnProperty.call(u, String(val)))
2860
- return false;
2861
- u[String(val)] = true;
2862
- return true;
2863
- });
3056
+ arr = toArray(arr);
3057
+ this.context.memoryLimit.use(arr.length);
3058
+ return [...new Set(arr)];
2864
3059
  }
2865
3060
  function sample(v, count = 1) {
2866
3061
  v = toValue(v);
@@ -2868,6 +3063,7 @@ function sample(v, count = 1) {
2868
3063
  return [];
2869
3064
  if (!isArray(v))
2870
3065
  v = stringify(v);
3066
+ this.context.memoryLimit.use(count);
2871
3067
  const shuffled = [...v].sort(() => Math.random() - 0.5);
2872
3068
  if (count === 1)
2873
3069
  return shuffled[0];
@@ -2903,6 +3099,9 @@ var arrayFilters = /*#__PURE__*/Object.freeze({
2903
3099
  });
2904
3100
 
2905
3101
  function date(v, format, timezoneOffset) {
3102
+ var _a, _b, _c;
3103
+ const size = ((_a = v === null || v === void 0 ? void 0 : v.length) !== null && _a !== void 0 ? _a : 0) + ((_b = format === null || format === void 0 ? void 0 : format.length) !== null && _b !== void 0 ? _b : 0) + ((_c = timezoneOffset === null || timezoneOffset === void 0 ? void 0 : timezoneOffset.length) !== null && _c !== void 0 ? _c : 0);
3104
+ this.context.memoryLimit.use(size);
2906
3105
  const date = parseDate(v, this.context.opts, timezoneOffset);
2907
3106
  if (!date)
2908
3107
  return v;
@@ -2936,39 +3135,30 @@ function stringify_date(v, month_type, type, style) {
2936
3135
  }
2937
3136
  function parseDate(v, opts, timezoneOffset) {
2938
3137
  let date;
3138
+ const defaultTimezoneOffset = timezoneOffset !== null && timezoneOffset !== void 0 ? timezoneOffset : opts.timezoneOffset;
3139
+ const locale = opts.locale;
2939
3140
  v = toValue(v);
2940
3141
  if (v === 'now' || v === 'today') {
2941
- date = new Date();
3142
+ date = new LiquidDate(Date.now(), locale, defaultTimezoneOffset);
2942
3143
  }
2943
3144
  else if (isNumber(v)) {
2944
- date = new Date(v * 1000);
3145
+ date = new LiquidDate(v * 1000, locale, defaultTimezoneOffset);
2945
3146
  }
2946
3147
  else if (isString(v)) {
2947
3148
  if (/^\d+$/.test(v)) {
2948
- date = new Date(+v * 1000);
3149
+ date = new LiquidDate(+v * 1000, locale, defaultTimezoneOffset);
2949
3150
  }
2950
- else if (opts.preserveTimezones) {
2951
- date = TimezoneDate.createDateFixedToTimezone(v);
3151
+ else if (opts.preserveTimezones && timezoneOffset === undefined) {
3152
+ date = LiquidDate.createDateFixedToTimezone(v, locale);
2952
3153
  }
2953
3154
  else {
2954
- date = new Date(v);
3155
+ date = new LiquidDate(v, locale, defaultTimezoneOffset);
2955
3156
  }
2956
3157
  }
2957
3158
  else {
2958
- date = v;
2959
- }
2960
- if (!isValidDate(date))
2961
- return;
2962
- if (timezoneOffset !== undefined) {
2963
- date = new TimezoneDate(date, timezoneOffset);
3159
+ date = new LiquidDate(v, locale, defaultTimezoneOffset);
2964
3160
  }
2965
- else if (!(date instanceof TimezoneDate) && opts.timezoneOffset !== undefined) {
2966
- date = new TimezoneDate(date, opts.timezoneOffset);
2967
- }
2968
- return date;
2969
- }
2970
- function isValidDate(date) {
2971
- return (date instanceof Date || date instanceof TimezoneDate) && !isNaN(date.getTime());
3161
+ return date.valid() ? date : undefined;
2972
3162
  }
2973
3163
 
2974
3164
  var dateFilters = /*#__PURE__*/Object.freeze({
@@ -2990,33 +3180,50 @@ const rCJKWord = /[\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF\u3040-\u309F\u30A0-\u
2990
3180
  const rNonCJKWord = /[^\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF\s]+/gu;
2991
3181
  function append(v, arg) {
2992
3182
  assert(arguments.length === 2, 'append expect 2 arguments');
2993
- return stringify(v) + stringify(arg);
3183
+ const lhs = stringify(v);
3184
+ const rhs = stringify(arg);
3185
+ this.context.memoryLimit.use(lhs.length + rhs.length);
3186
+ return lhs + rhs;
2994
3187
  }
2995
3188
  function prepend(v, arg) {
2996
3189
  assert(arguments.length === 2, 'prepend expect 2 arguments');
2997
- return stringify(arg) + stringify(v);
3190
+ const lhs = stringify(v);
3191
+ const rhs = stringify(arg);
3192
+ this.context.memoryLimit.use(lhs.length + rhs.length);
3193
+ return rhs + lhs;
2998
3194
  }
2999
3195
  function lstrip(v, chars) {
3196
+ const str = stringify(v);
3197
+ this.context.memoryLimit.use(str.length);
3000
3198
  if (chars) {
3001
3199
  chars = escapeRegExp(stringify(chars));
3002
- return stringify(v).replace(new RegExp(`^[${chars}]+`, 'g'), '');
3200
+ return str.replace(new RegExp(`^[${chars}]+`, 'g'), '');
3003
3201
  }
3004
- return stringify(v).replace(/^\s+/, '');
3202
+ return str.replace(/^\s+/, '');
3005
3203
  }
3006
3204
  function downcase(v) {
3007
- return stringify(v).toLowerCase();
3205
+ const str = stringify(v);
3206
+ this.context.memoryLimit.use(str.length);
3207
+ return str.toLowerCase();
3008
3208
  }
3009
- function upcase(str) {
3209
+ function upcase(v) {
3210
+ const str = stringify(v);
3211
+ this.context.memoryLimit.use(str.length);
3010
3212
  return stringify(str).toUpperCase();
3011
3213
  }
3012
3214
  function remove(v, arg) {
3013
- return stringify(v).split(stringify(arg)).join('');
3215
+ const str = stringify(v);
3216
+ this.context.memoryLimit.use(str.length);
3217
+ return str.split(stringify(arg)).join('');
3014
3218
  }
3015
3219
  function remove_first(v, l) {
3016
- return stringify(v).replace(stringify(l), '');
3220
+ const str = stringify(v);
3221
+ this.context.memoryLimit.use(str.length);
3222
+ return str.replace(stringify(l), '');
3017
3223
  }
3018
3224
  function remove_last(v, l) {
3019
3225
  const str = stringify(v);
3226
+ this.context.memoryLimit.use(str.length);
3020
3227
  const pattern = stringify(l);
3021
3228
  const index = str.lastIndexOf(pattern);
3022
3229
  if (index === -1)
@@ -3024,14 +3231,18 @@ function remove_last(v, l) {
3024
3231
  return str.substring(0, index) + str.substring(index + pattern.length);
3025
3232
  }
3026
3233
  function rstrip(str, chars) {
3234
+ str = stringify(str);
3235
+ this.context.memoryLimit.use(str.length);
3027
3236
  if (chars) {
3028
3237
  chars = escapeRegExp(stringify(chars));
3029
- return stringify(str).replace(new RegExp(`[${chars}]+$`, 'g'), '');
3238
+ return str.replace(new RegExp(`[${chars}]+$`, 'g'), '');
3030
3239
  }
3031
- return stringify(str).replace(/\s+$/, '');
3240
+ return str.replace(/\s+$/, '');
3032
3241
  }
3033
3242
  function split(v, arg) {
3034
- const arr = stringify(v).split(stringify(arg));
3243
+ const str = stringify(v);
3244
+ this.context.memoryLimit.use(str.length);
3245
+ const arr = str.split(stringify(arg));
3035
3246
  // align to ruby split, which is the behavior of shopify/liquid
3036
3247
  // see: https://ruby-doc.org/core-2.4.0/String.html#method-i-split
3037
3248
  while (arr.length && arr[arr.length - 1] === '')
@@ -3039,29 +3250,39 @@ function split(v, arg) {
3039
3250
  return arr;
3040
3251
  }
3041
3252
  function strip(v, chars) {
3253
+ const str = stringify(v);
3254
+ this.context.memoryLimit.use(str.length);
3042
3255
  if (chars) {
3043
3256
  chars = escapeRegExp(stringify(chars));
3044
- return stringify(v)
3257
+ return str
3045
3258
  .replace(new RegExp(`^[${chars}]+`, 'g'), '')
3046
3259
  .replace(new RegExp(`[${chars}]+$`, 'g'), '');
3047
3260
  }
3048
- return stringify(v).trim();
3261
+ return str.trim();
3049
3262
  }
3050
3263
  function strip_newlines(v) {
3051
- return stringify(v).replace(/\r?\n/gm, '');
3264
+ const str = stringify(v);
3265
+ this.context.memoryLimit.use(str.length);
3266
+ return str.replace(/\r?\n/gm, '');
3052
3267
  }
3053
3268
  function capitalize(str) {
3054
3269
  str = stringify(str);
3270
+ this.context.memoryLimit.use(str.length);
3055
3271
  return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
3056
3272
  }
3057
3273
  function replace(v, pattern, replacement) {
3058
- return stringify(v).split(stringify(pattern)).join(replacement);
3274
+ const str = stringify(v);
3275
+ this.context.memoryLimit.use(str.length);
3276
+ return str.split(stringify(pattern)).join(replacement);
3059
3277
  }
3060
3278
  function replace_first(v, arg1, arg2) {
3061
- return stringify(v).replace(stringify(arg1), arg2);
3279
+ const str = stringify(v);
3280
+ this.context.memoryLimit.use(str.length);
3281
+ return str.replace(stringify(arg1), arg2);
3062
3282
  }
3063
3283
  function replace_last(v, arg1, arg2) {
3064
3284
  const str = stringify(v);
3285
+ this.context.memoryLimit.use(str.length);
3065
3286
  const pattern = stringify(arg1);
3066
3287
  const index = str.lastIndexOf(pattern);
3067
3288
  if (index === -1)
@@ -3070,13 +3291,16 @@ function replace_last(v, arg1, arg2) {
3070
3291
  return str.substring(0, index) + replacement + str.substring(index + pattern.length);
3071
3292
  }
3072
3293
  function truncate(v, l = 50, o = '...') {
3073
- v = stringify(v);
3074
- if (v.length <= l)
3294
+ const str = stringify(v);
3295
+ this.context.memoryLimit.use(str.length);
3296
+ if (str.length <= l)
3075
3297
  return v;
3076
- return v.substring(0, l - o.length) + o;
3298
+ return str.substring(0, l - o.length) + o;
3077
3299
  }
3078
3300
  function truncatewords(v, words = 15, o = '...') {
3079
- const arr = stringify(v).split(/\s+/);
3301
+ const str = stringify(v);
3302
+ this.context.memoryLimit.use(str.length);
3303
+ const arr = str.split(/\s+/);
3080
3304
  if (words <= 0)
3081
3305
  words = 1;
3082
3306
  let ret = arr.slice(0, words).join(' ');
@@ -3085,11 +3309,14 @@ function truncatewords(v, words = 15, o = '...') {
3085
3309
  return ret;
3086
3310
  }
3087
3311
  function normalize_whitespace(v) {
3088
- v = stringify(v);
3089
- return v.replace(/\s+/g, ' ');
3312
+ const str = stringify(v);
3313
+ this.context.memoryLimit.use(str.length);
3314
+ return str.replace(/\s+/g, ' ');
3090
3315
  }
3091
3316
  function number_of_words(input, mode) {
3092
- input = stringify(input).trim();
3317
+ const str = stringify(input);
3318
+ this.context.memoryLimit.use(str.length);
3319
+ input = str.trim();
3093
3320
  if (!input)
3094
3321
  return 0;
3095
3322
  switch (mode) {
@@ -3107,6 +3334,7 @@ function number_of_words(input, mode) {
3107
3334
  }
3108
3335
  }
3109
3336
  function array_to_sentence_string(array, connector = 'and') {
3337
+ this.context.memoryLimit.use(array.length);
3110
3338
  switch (array.length) {
3111
3339
  case 0:
3112
3340
  return '';
@@ -3163,7 +3391,7 @@ class AssignTag extends Tag {
3163
3391
 
3164
3392
  const MODIFIERS = ['offset', 'limit', 'reversed'];
3165
3393
  class ForTag extends Tag {
3166
- constructor(token, remainTokens, liquid) {
3394
+ constructor(token, remainTokens, liquid, parser) {
3167
3395
  super(token, remainTokens, liquid);
3168
3396
  const variable = this.tokenizer.readIdentifier();
3169
3397
  const inStr = this.tokenizer.readIdentifier();
@@ -3173,18 +3401,16 @@ class ForTag extends Tag {
3173
3401
  }
3174
3402
  this.variable = variable.content;
3175
3403
  this.collection = collection;
3176
- this.hash = new Hash(this.tokenizer.remaining());
3404
+ this.hash = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
3177
3405
  this.templates = [];
3178
3406
  this.elseTemplates = [];
3179
3407
  let p;
3180
- const stream = this.liquid.parser.parseStream(remainTokens)
3408
+ const stream = parser.parseStream(remainTokens)
3181
3409
  .on('start', () => (p = this.templates))
3182
- .on('tag:else', () => (p = this.elseTemplates))
3183
- .on('tag:endfor', () => stream.stop())
3410
+ .on('tag:else', tag => { assertEmpty(tag.args); p = this.elseTemplates; })
3411
+ .on('tag:endfor', tag => { assertEmpty(tag.args); stream.stop(); })
3184
3412
  .on('template', (tpl) => p.push(tpl))
3185
- .on('end', () => {
3186
- throw new Error(`tag ${token.getText()} not closed`);
3187
- });
3413
+ .on('end', () => { throw new Error(`tag ${token.getText()} not closed`); });
3188
3414
  stream.start();
3189
3415
  }
3190
3416
  *render(ctx, emitter) {
@@ -3235,7 +3461,7 @@ function limit(arr, count) {
3235
3461
  }
3236
3462
 
3237
3463
  class CaptureTag extends Tag {
3238
- constructor(tagToken, remainTokens, liquid) {
3464
+ constructor(tagToken, remainTokens, liquid, parser) {
3239
3465
  super(tagToken, remainTokens, liquid);
3240
3466
  this.templates = [];
3241
3467
  this.variable = this.readVariableName();
@@ -3243,7 +3469,7 @@ class CaptureTag extends Tag {
3243
3469
  const token = remainTokens.shift();
3244
3470
  if (isTagToken(token) && token.name === 'endcapture')
3245
3471
  return;
3246
- this.templates.push(liquid.parser.parseToken(token, remainTokens));
3472
+ this.templates.push(parser.parseToken(token, remainTokens));
3247
3473
  }
3248
3474
  throw new Error(`tag ${tagToken.getText()} not closed`);
3249
3475
  }
@@ -3264,7 +3490,7 @@ class CaptureTag extends Tag {
3264
3490
  }
3265
3491
 
3266
3492
  class CaseTag extends Tag {
3267
- constructor(tagToken, remainTokens, liquid) {
3493
+ constructor(tagToken, remainTokens, liquid, parser) {
3268
3494
  super(tagToken, remainTokens, liquid);
3269
3495
  this.branches = [];
3270
3496
  this.elseTemplates = [];
@@ -3272,7 +3498,7 @@ class CaseTag extends Tag {
3272
3498
  this.elseTemplates = [];
3273
3499
  let p = [];
3274
3500
  let elseCount = 0;
3275
- const stream = this.liquid.parser.parseStream(remainTokens)
3501
+ const stream = parser.parseStream(remainTokens)
3276
3502
  .on('tag:when', (token) => {
3277
3503
  if (elseCount > 0) {
3278
3504
  return;
@@ -3343,10 +3569,10 @@ class CommentTag extends Tag {
3343
3569
  }
3344
3570
 
3345
3571
  class RenderTag extends Tag {
3346
- constructor(token, remainTokens, liquid) {
3572
+ constructor(token, remainTokens, liquid, parser) {
3347
3573
  super(token, remainTokens, liquid);
3348
3574
  const tokenizer = this.tokenizer;
3349
- this.file = parseFilePath(tokenizer, this.liquid);
3575
+ this.file = parseFilePath(tokenizer, this.liquid, parser);
3350
3576
  this.currentFile = token.file;
3351
3577
  while (!tokenizer.end()) {
3352
3578
  tokenizer.skipBlank();
@@ -3380,13 +3606,13 @@ class RenderTag extends Tag {
3380
3606
  tokenizer.p = begin;
3381
3607
  break;
3382
3608
  }
3383
- this.hash = new Hash(tokenizer.remaining());
3609
+ this.hash = new Hash(tokenizer.remaining(), liquid.options.keyValueSeparator);
3384
3610
  }
3385
3611
  *render(ctx, emitter) {
3386
3612
  const { liquid, hash } = this;
3387
3613
  const filepath = (yield renderFilePath(this['file'], ctx, liquid));
3388
3614
  assert(filepath, () => `illegal file path "${filepath}"`);
3389
- const childCtx = new Context({}, ctx.opts, { sync: ctx.sync, globals: ctx.globals, strictVariables: ctx.strictVariables });
3615
+ const childCtx = ctx.spawn();
3390
3616
  const scope = childCtx.bottom();
3391
3617
  __assign(scope, yield hash.render(ctx));
3392
3618
  if (this['with']) {
@@ -3416,7 +3642,7 @@ class RenderTag extends Tag {
3416
3642
  * @return Token for expression (not quoted)
3417
3643
  * @throws TypeError if cannot read next token
3418
3644
  */
3419
- function parseFilePath(tokenizer, liquid) {
3645
+ function parseFilePath(tokenizer, liquid, parser) {
3420
3646
  if (liquid.options.dynamicPartials) {
3421
3647
  const file = tokenizer.readValue();
3422
3648
  tokenizer.assert(file, 'illegal file path');
@@ -3424,13 +3650,13 @@ function parseFilePath(tokenizer, liquid) {
3424
3650
  return;
3425
3651
  if (isQuotedToken(file)) {
3426
3652
  // for filenames like "files/{{file}}", eval as liquid template
3427
- const templates = liquid.parse(evalQuotedToken(file));
3653
+ const templates = parser.parse(evalQuotedToken(file));
3428
3654
  return optimize(templates);
3429
3655
  }
3430
3656
  return file;
3431
3657
  }
3432
3658
  const tokens = [...tokenizer.readFileNameTemplate(liquid.options)];
3433
- const templates = optimize(liquid.parser.parseTokens(tokens));
3659
+ const templates = optimize(parser.parseTokens(tokens));
3434
3660
  return templates === 'none' ? undefined : templates;
3435
3661
  }
3436
3662
  function optimize(templates) {
@@ -3448,10 +3674,10 @@ function* renderFilePath(file, ctx, liquid) {
3448
3674
  }
3449
3675
 
3450
3676
  class IncludeTag extends Tag {
3451
- constructor(token, remainTokens, liquid) {
3677
+ constructor(token, remainTokens, liquid, parser) {
3452
3678
  super(token, remainTokens, liquid);
3453
3679
  const { tokenizer } = token;
3454
- this['file'] = parseFilePath(tokenizer, this.liquid);
3680
+ this['file'] = parseFilePath(tokenizer, this.liquid, parser);
3455
3681
  this['currentFile'] = token.file;
3456
3682
  const begin = tokenizer.p;
3457
3683
  const withStr = tokenizer.readIdentifier();
@@ -3465,7 +3691,7 @@ class IncludeTag extends Tag {
3465
3691
  }
3466
3692
  else
3467
3693
  tokenizer.p = begin;
3468
- this.hash = new Hash(tokenizer.remaining(), this.liquid.options.jekyllInclude);
3694
+ this.hash = new Hash(tokenizer.remaining(), liquid.options.jekyllInclude || liquid.options.keyValueSeparator);
3469
3695
  }
3470
3696
  *render(ctx, emitter) {
3471
3697
  const { liquid, hash, withVar } = this;
@@ -3538,37 +3764,29 @@ class CycleTag extends Tag {
3538
3764
  }
3539
3765
 
3540
3766
  class IfTag extends Tag {
3541
- constructor(tagToken, remainTokens, liquid) {
3767
+ constructor(tagToken, remainTokens, liquid, parser) {
3542
3768
  super(tagToken, remainTokens, liquid);
3543
3769
  this.branches = [];
3544
- this.elseTemplates = [];
3545
3770
  let p = [];
3546
- let elseCount = 0;
3547
- liquid.parser.parseStream(remainTokens)
3771
+ parser.parseStream(remainTokens)
3548
3772
  .on('start', () => this.branches.push({
3549
3773
  value: new Value(tagToken.args, this.liquid),
3550
3774
  templates: (p = [])
3551
3775
  }))
3552
3776
  .on('tag:elsif', (token) => {
3553
- if (elseCount > 0) {
3554
- p = [];
3555
- return;
3556
- }
3777
+ assert(!this.elseTemplates, 'unexpected elsif after else');
3557
3778
  this.branches.push({
3558
3779
  value: new Value(token.args, this.liquid),
3559
3780
  templates: (p = [])
3560
3781
  });
3561
3782
  })
3562
- .on('tag:else', () => {
3563
- elseCount++;
3564
- p = this.elseTemplates;
3565
- })
3566
- .on('tag:endif', function () { this.stop(); })
3567
- .on('template', (tpl) => {
3568
- if (p !== this.elseTemplates || elseCount === 1) {
3569
- p.push(tpl);
3570
- }
3783
+ .on('tag:else', tag => {
3784
+ assertEmpty(tag.args);
3785
+ assert(!this.elseTemplates, 'duplicated else');
3786
+ p = this.elseTemplates = [];
3571
3787
  })
3788
+ .on('tag:endif', function (tag) { assertEmpty(tag.args); this.stop(); })
3789
+ .on('template', (tpl) => p.push(tpl))
3572
3790
  .on('end', () => { throw new Error(`tag ${tagToken.getText()} not closed`); })
3573
3791
  .start();
3574
3792
  }
@@ -3581,7 +3799,7 @@ class IfTag extends Tag {
3581
3799
  return;
3582
3800
  }
3583
3801
  }
3584
- yield r.renderTemplates(this.elseTemplates, ctx, emitter);
3802
+ yield r.renderTemplates(this.elseTemplates || [], ctx, emitter);
3585
3803
  }
3586
3804
  }
3587
3805
 
@@ -3602,12 +3820,12 @@ class IncrementTag extends Tag {
3602
3820
  }
3603
3821
 
3604
3822
  class LayoutTag extends Tag {
3605
- constructor(token, remainTokens, liquid) {
3823
+ constructor(token, remainTokens, liquid, parser) {
3606
3824
  super(token, remainTokens, liquid);
3607
- this.file = parseFilePath(this.tokenizer, this.liquid);
3825
+ this.file = parseFilePath(this.tokenizer, this.liquid, parser);
3608
3826
  this['currentFile'] = token.file;
3609
- this.args = new Hash(this.tokenizer.remaining());
3610
- this.templates = this.liquid.parser.parseTokens(remainTokens);
3827
+ this.args = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
3828
+ this.templates = parser.parseTokens(remainTokens);
3611
3829
  }
3612
3830
  *render(ctx, emitter) {
3613
3831
  const { liquid, args, file } = this;
@@ -3636,7 +3854,7 @@ class LayoutTag extends Tag {
3636
3854
  }
3637
3855
 
3638
3856
  class BlockTag extends Tag {
3639
- constructor(token, remainTokens, liquid) {
3857
+ constructor(token, remainTokens, liquid, parser) {
3640
3858
  super(token, remainTokens, liquid);
3641
3859
  this.templates = [];
3642
3860
  const match = /\w+/.exec(token.args);
@@ -3645,7 +3863,7 @@ class BlockTag extends Tag {
3645
3863
  const token = remainTokens.shift();
3646
3864
  if (isTagToken(token) && token.name === 'endblock')
3647
3865
  return;
3648
- const template = liquid.parser.parseToken(token, remainTokens);
3866
+ const template = parser.parseToken(token, remainTokens);
3649
3867
  this.templates.push(template);
3650
3868
  }
3651
3869
  throw new Error(`tag ${token.getText()} not closed`);
@@ -3715,7 +3933,7 @@ class TablerowloopDrop extends ForloopDrop {
3715
3933
  }
3716
3934
 
3717
3935
  class TablerowTag extends Tag {
3718
- constructor(tagToken, remainTokens, liquid) {
3936
+ constructor(tagToken, remainTokens, liquid, parser) {
3719
3937
  super(tagToken, remainTokens, liquid);
3720
3938
  const variable = this.tokenizer.readIdentifier();
3721
3939
  this.tokenizer.skipBlank();
@@ -3726,10 +3944,10 @@ class TablerowTag extends Tag {
3726
3944
  }
3727
3945
  this.variable = variable.content;
3728
3946
  this.collection = collectionToken;
3729
- this.args = new Hash(this.tokenizer.remaining());
3947
+ this.args = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
3730
3948
  this.templates = [];
3731
3949
  let p;
3732
- const stream = this.liquid.parser.parseStream(remainTokens)
3950
+ const stream = parser.parseStream(remainTokens)
3733
3951
  .on('start', () => (p = this.templates))
3734
3952
  .on('tag:endtablerow', () => stream.stop())
3735
3953
  .on('template', (tpl) => p.push(tpl))
@@ -3767,13 +3985,13 @@ class TablerowTag extends Tag {
3767
3985
  }
3768
3986
 
3769
3987
  class UnlessTag extends Tag {
3770
- constructor(tagToken, remainTokens, liquid) {
3988
+ constructor(tagToken, remainTokens, liquid, parser) {
3771
3989
  super(tagToken, remainTokens, liquid);
3772
3990
  this.branches = [];
3773
3991
  this.elseTemplates = [];
3774
3992
  let p = [];
3775
3993
  let elseCount = 0;
3776
- this.liquid.parser.parseStream(remainTokens)
3994
+ parser.parseStream(remainTokens)
3777
3995
  .on('start', () => this.branches.push({
3778
3996
  value: new Value(tagToken.args, this.liquid),
3779
3997
  test: isFalsy,
@@ -3845,10 +4063,10 @@ class EchoTag extends Tag {
3845
4063
  }
3846
4064
 
3847
4065
  class LiquidTag extends Tag {
3848
- constructor(token, remainTokens, liquid) {
4066
+ constructor(token, remainTokens, liquid, parser) {
3849
4067
  super(token, remainTokens, liquid);
3850
4068
  const tokens = this.tokenizer.readLiquidTagTokens(this.liquid.options);
3851
- this.templates = this.liquid.parser.parseTokens(tokens);
4069
+ this.templates = parser.parseTokens(tokens);
3852
4070
  }
3853
4071
  *render(ctx, emitter) {
3854
4072
  yield this.liquid.renderer.renderTemplates(this.templates, ctx, emitter);
@@ -3895,12 +4113,14 @@ class Liquid {
3895
4113
  this.filters = {};
3896
4114
  this.tags = {};
3897
4115
  this.options = normalize(opts);
4116
+ // eslint-disable-next-line deprecation/deprecation
3898
4117
  this.parser = new Parser(this);
3899
4118
  forOwn(tags, (conf, name) => this.registerTag(name, conf));
3900
4119
  forOwn(filters, (handler, name) => this.registerFilter(name, handler));
3901
4120
  }
3902
4121
  parse(html, filepath) {
3903
- return this.parser.parse(html, filepath);
4122
+ const parser = new Parser(this);
4123
+ return parser.parse(html, filepath);
3904
4124
  }
3905
4125
  _render(tpl, scope, renderOptions) {
3906
4126
  const ctx = scope instanceof Context ? scope : new Context(scope, this.options, renderOptions);
@@ -3931,21 +4151,21 @@ class Liquid {
3931
4151
  return toValueSync(this._parseAndRender(html, scope, Object.assign(Object.assign({}, renderOptions), { sync: true })));
3932
4152
  }
3933
4153
  _parsePartialFile(file, sync, currentFile) {
3934
- return this.parser.parseFile(file, sync, LookupType.Partials, currentFile);
4154
+ return new Parser(this).parseFile(file, sync, LookupType.Partials, currentFile);
3935
4155
  }
3936
4156
  _parseLayoutFile(file, sync, currentFile) {
3937
- return this.parser.parseFile(file, sync, LookupType.Layouts, currentFile);
4157
+ return new Parser(this).parseFile(file, sync, LookupType.Layouts, currentFile);
3938
4158
  }
3939
4159
  _parseFile(file, sync, lookupType, currentFile) {
3940
- return this.parser.parseFile(file, sync, lookupType, currentFile);
4160
+ return new Parser(this).parseFile(file, sync, lookupType, currentFile);
3941
4161
  }
3942
4162
  parseFile(file, lookupType) {
3943
4163
  return __awaiter(this, void 0, void 0, function* () {
3944
- return toPromise(this.parser.parseFile(file, false, lookupType));
4164
+ return toPromise(new Parser(this).parseFile(file, false, lookupType));
3945
4165
  });
3946
4166
  }
3947
4167
  parseFileSync(file, lookupType) {
3948
- return toValueSync(this.parser.parseFile(file, true, lookupType));
4168
+ return toValueSync(new Parser(this).parseFile(file, true, lookupType));
3949
4169
  }
3950
4170
  *_renderFile(file, ctx, renderFileOptions) {
3951
4171
  const templates = (yield this._parseFile(file, renderFileOptions.sync, renderFileOptions.lookupType));
@@ -4004,6 +4224,6 @@ class Liquid {
4004
4224
  }
4005
4225
 
4006
4226
  /* istanbul ignore file */
4007
- const version = '10.13.0';
4227
+ const version = '[VI]{version}[/VI]';
4008
4228
 
4009
- 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, TimezoneDate, Token, TokenKind, TokenizationError, Tokenizer, typeGuards as TypeGuards, UndefinedVariableError, UnlessTag, Value, assert, createTrie, defaultOperators, defaultOptions, evalQuotedToken, evalToken, filters, isFalsy, isTruthy, tags, toPromise, toValue, toValueSync, version };
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 };