@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,5 +1,5 @@
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
  */
@@ -89,6 +89,10 @@ function toArray(val) {
89
89
  function toValue(value) {
90
90
  return (value instanceof Drop && isFunction(value.valueOf)) ? value.valueOf() : value;
91
91
  }
92
+ function toNumber(value) {
93
+ value = Number(value);
94
+ return isNaN(value) ? 0 : value;
95
+ }
92
96
  function isNumber(value) {
93
97
  return typeof value === 'number';
94
98
  }
@@ -188,14 +192,14 @@ function caseInsensitiveCompare(a, b) {
188
192
  return 0;
189
193
  }
190
194
  function argumentsToValue(fn) {
191
- return (...args) => fn(...args.map(toValue));
195
+ return function (...args) { return fn.call(this, ...args.map(toValue)); };
192
196
  }
193
197
  function escapeRegExp(text) {
194
198
  return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
195
199
  }
196
200
 
197
201
  /**
198
- * targeting ES5, extends Error won't create a proper prototype chain, need a trait to kee track of classes
202
+ * targeting ES5, extends Error won't create a proper prototype chain, need a trait to keep track of classes
199
203
  */
200
204
  const TRAIT = '__liquidClass__';
201
205
  class LiquidError extends Error {
@@ -249,6 +253,19 @@ class RenderError extends LiquidError {
249
253
  return obj.name === 'RenderError';
250
254
  }
251
255
  }
256
+ class LiquidErrors extends LiquidError {
257
+ constructor(errors) {
258
+ super(errors[0], errors[0].token);
259
+ this.errors = errors;
260
+ this.name = 'LiquidErrors';
261
+ const s = errors.length > 1 ? 's' : '';
262
+ this.message = `${errors.length} error${s} found`;
263
+ super.update();
264
+ }
265
+ static is(obj) {
266
+ return obj.name === 'LiquidErrors';
267
+ }
268
+ }
252
269
  class UndefinedVariableError extends LiquidError {
253
270
  constructor(err, token) {
254
271
  super(err, token);
@@ -327,6 +344,9 @@ function assert(predicate, message) {
327
344
  : (message || `expect ${predicate} to be true`);
328
345
  throw new AssertionError(msg);
329
346
  }
347
+ }
348
+ function assertEmpty(predicate, message = `unexpected ${JSON.stringify(predicate)}`) {
349
+ assert(!predicate, message);
330
350
  }
331
351
 
332
352
  class NullDrop extends Drop {
@@ -440,7 +460,12 @@ class BlockDrop extends Drop {
440
460
  }
441
461
 
442
462
  function isComparable(arg) {
443
- return arg && isFunction(arg.equals);
463
+ return (arg &&
464
+ isFunction(arg.equals) &&
465
+ isFunction(arg.gt) &&
466
+ isFunction(arg.geq) &&
467
+ isFunction(arg.lt) &&
468
+ isFunction(arg.leq));
444
469
  }
445
470
 
446
471
  const nil = new NullDrop();
@@ -560,18 +585,6 @@ function toValueSync(val) {
560
585
  }
561
586
 
562
587
  const rFormat = /%([-_0^#:]+)?(\d+)?([EO])?(.)/;
563
- const monthNames = [
564
- 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
565
- 'September', 'October', 'November', 'December'
566
- ];
567
- const dayNames = [
568
- 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
569
- ];
570
- const monthNamesShort = monthNames.map(abbr);
571
- const dayNamesShort = dayNames.map(abbr);
572
- function abbr(str) {
573
- return str.slice(0, 3);
574
- }
575
588
  // prototype extensions
576
589
  function daysInMonth(d) {
577
590
  const feb = isLeapYear(d) ? 29 : 28;
@@ -626,19 +639,7 @@ const padWidths = {
626
639
  U: 2,
627
640
  W: 2
628
641
  };
629
- // default to '0'
630
- const padChars = {
631
- a: ' ',
632
- A: ' ',
633
- b: ' ',
634
- B: ' ',
635
- c: ' ',
636
- e: ' ',
637
- k: ' ',
638
- l: ' ',
639
- p: ' ',
640
- P: ' '
641
- };
642
+ const padSpaceChars = new Set('aAbBceklpP');
642
643
  function getTimezoneOffset(d, opts) {
643
644
  const nOffset = Math.abs(d.getTimezoneOffset());
644
645
  const h = Math.floor(nOffset / 60);
@@ -649,10 +650,10 @@ function getTimezoneOffset(d, opts) {
649
650
  padStart(m, 2, '0');
650
651
  }
651
652
  const formatCodes = {
652
- a: (d) => dayNamesShort[d.getDay()],
653
- A: (d) => dayNames[d.getDay()],
654
- b: (d) => monthNamesShort[d.getMonth()],
655
- B: (d) => monthNames[d.getMonth()],
653
+ a: (d) => d.getShortWeekdayName(),
654
+ A: (d) => d.getLongWeekdayName(),
655
+ b: (d) => d.getShortMonthName(),
656
+ B: (d) => d.getLongMonthName(),
656
657
  c: (d) => d.toLocaleString(),
657
658
  C: (d) => century(d),
658
659
  d: (d) => d.getDate(),
@@ -684,12 +685,7 @@ const formatCodes = {
684
685
  y: (d) => d.getFullYear().toString().slice(2, 4),
685
686
  Y: (d) => d.getFullYear(),
686
687
  z: getTimezoneOffset,
687
- Z: (d, opts) => {
688
- if (d.getTimezoneName) {
689
- return d.getTimezoneName() || getTimezoneOffset(d, opts);
690
- }
691
- return (typeof Intl !== 'undefined' ? Intl.DateTimeFormat().resolvedOptions().timeZone : '');
692
- },
688
+ Z: (d, opts) => d.getTimeZoneName() || getTimezoneOffset(d, opts),
693
689
  't': () => '\t',
694
690
  'n': () => '\n',
695
691
  '%': () => '%'
@@ -715,7 +711,7 @@ function format(d, match) {
715
711
  for (const flag of flagStr)
716
712
  flags[flag] = true;
717
713
  let ret = String(convert(d, { flags, width, modifier }));
718
- let padChar = padChars[conversion] || '0';
714
+ let padChar = padSpaceChars.has(conversion) ? ' ' : '0';
719
715
  let padWidth = width || padWidths[conversion] || 0;
720
716
  if (flags['^'])
721
717
  ret = ret.toUpperCase();
@@ -730,9 +726,22 @@ function format(d, match) {
730
726
  return padStart(ret, padWidth, padChar);
731
727
  }
732
728
 
729
+ function getDateTimeFormat() {
730
+ return (typeof Intl !== 'undefined' ? Intl.DateTimeFormat : undefined);
731
+ }
732
+
733
733
  // one minute in milliseconds
734
734
  const OneMinute = 60000;
735
735
  const ISO8601_TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):(\d{2}))$/;
736
+ const monthNames = [
737
+ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
738
+ 'September', 'October', 'November', 'December'
739
+ ];
740
+ const monthNamesShort = monthNames.map(name => name.slice(0, 3));
741
+ const dayNames = [
742
+ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
743
+ ];
744
+ const dayNamesShort = dayNames.map(name => name.slice(0, 3));
736
745
  /**
737
746
  * A date implementation with timezone info, just like Ruby date
738
747
  *
@@ -740,12 +749,16 @@ const ISO8601_TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):(\d{2}))$/;
740
749
  * - create a Date offset by it's timezone difference, avoiding overriding a bunch of methods
741
750
  * - rewrite getTimezoneOffset() to trick strftime
742
751
  */
743
- class TimezoneDate {
744
- constructor(init, timezone) {
745
- this.date = init instanceof TimezoneDate
746
- ? init.date
747
- : new Date(init);
748
- this.timezoneOffset = isString(timezone) ? TimezoneDate.getTimezoneOffset(timezone, this.date) : timezone;
752
+ class LiquidDate {
753
+ constructor(init, locale, timezone) {
754
+ this.locale = locale;
755
+ this.DateTimeFormat = getDateTimeFormat();
756
+ this.date = new Date(init);
757
+ this.timezoneFixed = timezone !== undefined;
758
+ if (timezone === undefined) {
759
+ timezone = this.date.getTimezoneOffset();
760
+ }
761
+ this.timezoneOffset = isString(timezone) ? LiquidDate.getTimezoneOffset(timezone, this.date) : timezone;
749
762
  this.timezoneName = isString(timezone) ? timezone : '';
750
763
  const diff = (this.date.getTimezoneOffset() - this.timezoneOffset) * OneMinute;
751
764
  const time = this.date.getTime() + diff;
@@ -793,8 +806,34 @@ class TimezoneDate {
793
806
  getTimezoneOffset() {
794
807
  return this.timezoneOffset;
795
808
  }
796
- getTimezoneName() {
797
- return this.timezoneName;
809
+ getTimeZoneName() {
810
+ if (this.timezoneFixed)
811
+ return this.timezoneName;
812
+ if (!this.DateTimeFormat)
813
+ return;
814
+ return this.DateTimeFormat().resolvedOptions().timeZone;
815
+ }
816
+ getLongMonthName() {
817
+ var _a;
818
+ return (_a = this.format({ month: 'long' })) !== null && _a !== void 0 ? _a : monthNames[this.getMonth()];
819
+ }
820
+ getShortMonthName() {
821
+ var _a;
822
+ return (_a = this.format({ month: 'short' })) !== null && _a !== void 0 ? _a : monthNamesShort[this.getMonth()];
823
+ }
824
+ getLongWeekdayName() {
825
+ var _a;
826
+ return (_a = this.format({ weekday: 'long' })) !== null && _a !== void 0 ? _a : dayNames[this.displayDate.getDay()];
827
+ }
828
+ getShortWeekdayName() {
829
+ var _a;
830
+ return (_a = this.format({ weekday: 'short' })) !== null && _a !== void 0 ? _a : dayNamesShort[this.displayDate.getDay()];
831
+ }
832
+ valid() {
833
+ return !isNaN(this.getTime());
834
+ }
835
+ format(options) {
836
+ return this.DateTimeFormat && this.DateTimeFormat(this.locale, options).format(this.displayDate);
798
837
  }
799
838
  /**
800
839
  * Create a Date object fixed to it's declared Timezone. Both
@@ -809,21 +848,21 @@ class TimezoneDate {
809
848
  * we create a different Date to trick strftime, it's both simpler and more performant.
810
849
  * Given that a template is expected to be parsed fewer times than rendered.
811
850
  */
812
- static createDateFixedToTimezone(dateString) {
851
+ static createDateFixedToTimezone(dateString, locale) {
813
852
  const m = dateString.match(ISO8601_TIMEZONE_PATTERN);
814
853
  // representing a UTC timestamp
815
854
  if (m && m[1] === 'Z') {
816
- return new TimezoneDate(+new Date(dateString), 0);
855
+ return new LiquidDate(+new Date(dateString), locale, 0);
817
856
  }
818
857
  // has a timezone specified
819
858
  if (m && m[2] && m[3] && m[4]) {
820
859
  const [, , sign, hours, minutes] = m;
821
860
  const offset = (sign === '+' ? -1 : 1) * (parseInt(hours, 10) * 60 + parseInt(minutes, 10));
822
- return new TimezoneDate(+new Date(dateString), offset);
861
+ return new LiquidDate(+new Date(dateString), locale, offset);
823
862
  }
824
- return new Date(dateString);
863
+ return new LiquidDate(dateString, locale);
825
864
  }
826
- static getTimezoneOffset(timezoneName, date = new Date()) {
865
+ static getTimezoneOffset(timezoneName, date) {
827
866
  const localDateString = date.toLocaleString('en-US', { timeZone: timezoneName });
828
867
  const utcDateString = date.toLocaleString('en-US', { timeZone: 'UTC' });
829
868
  const localDate = new Date(localDateString);
@@ -832,6 +871,23 @@ class TimezoneDate {
832
871
  }
833
872
  }
834
873
 
874
+ class Limiter {
875
+ constructor(resource, limit) {
876
+ this.base = 0;
877
+ this.message = `${resource} limit exceeded`;
878
+ this.limit = limit;
879
+ }
880
+ use(count) {
881
+ count = toNumber(count);
882
+ assert(this.base + count <= this.limit, this.message);
883
+ this.base += count;
884
+ }
885
+ check(count) {
886
+ count = toNumber(count);
887
+ assert(count <= this.limit, this.message);
888
+ }
889
+ }
890
+
835
891
  class DelimitedToken extends Token {
836
892
  constructor(kind, [contentBegin, contentEnd], input, begin, end, trimLeft, trimRight, file) {
837
893
  super(kind, input, begin, end, file);
@@ -912,16 +968,6 @@ class IdentifierToken extends Token {
912
968
  this.file = file;
913
969
  this.content = this.getText();
914
970
  }
915
- isNumber(allowSign = false) {
916
- const begin = allowSign && TYPES[this.input.charCodeAt(this.begin)] & SIGN
917
- ? this.begin + 1
918
- : this.begin;
919
- for (let i = begin; i < this.end; i++) {
920
- if (!(TYPES[this.input.charCodeAt(i)] & NUMBER))
921
- return false;
922
- }
923
- return true;
924
- }
925
971
  }
926
972
 
927
973
  class LiteralToken extends Token {
@@ -1110,6 +1156,15 @@ class FilteredValueToken extends Token {
1110
1156
  }
1111
1157
  }
1112
1158
 
1159
+ const polyfill = {
1160
+ now: () => Date.now()
1161
+ };
1162
+ function getPerformance() {
1163
+ return (typeof global === 'object' && global.performance) ||
1164
+ (typeof window === 'object' && window.performance) ||
1165
+ polyfill;
1166
+ }
1167
+
1113
1168
  class SimpleEmitter {
1114
1169
  constructor() {
1115
1170
  this.buffer = '';
@@ -1157,7 +1212,9 @@ class Render {
1157
1212
  if (!emitter) {
1158
1213
  emitter = ctx.opts.keepOutputType ? new KeepingTypeEmitter() : new SimpleEmitter();
1159
1214
  }
1215
+ const errors = [];
1160
1216
  for (const tpl of templates) {
1217
+ ctx.renderLimit.check(getPerformance().now());
1161
1218
  try {
1162
1219
  // if tpl.render supports emitter, it'll return empty `html`
1163
1220
  const html = yield tpl.render(ctx, emitter);
@@ -1167,10 +1224,16 @@ class Render {
1167
1224
  break;
1168
1225
  }
1169
1226
  catch (e) {
1170
- const err = RenderError.is(e) ? e : new RenderError(e, tpl);
1171
- throw err;
1227
+ const err = LiquidError.is(e) ? e : new RenderError(e, tpl);
1228
+ if (ctx.opts.catchAllErrors)
1229
+ errors.push(err);
1230
+ else
1231
+ throw err;
1172
1232
  }
1173
1233
  }
1234
+ if (errors.length) {
1235
+ throw new LiquidErrors(errors);
1236
+ }
1174
1237
  return emitter.buffer;
1175
1238
  }
1176
1239
  }
@@ -1264,6 +1327,7 @@ function isTruthy(val, ctx) {
1264
1327
  return !isFalsy(val, ctx);
1265
1328
  }
1266
1329
  function isFalsy(val, ctx) {
1330
+ val = toValue(val);
1267
1331
  if (ctx.opts.jsTruthy) {
1268
1332
  return !val;
1269
1333
  }
@@ -1522,22 +1586,30 @@ const unescapeMap = {
1522
1586
  '&#39;': "'"
1523
1587
  };
1524
1588
  function escape(str) {
1525
- return stringify(str).replace(/&|<|>|"|'/g, m => escapeMap[m]);
1589
+ str = stringify(str);
1590
+ this.context.memoryLimit.use(str.length);
1591
+ return str.replace(/&|<|>|"|'/g, m => escapeMap[m]);
1526
1592
  }
1527
1593
  function xml_escape(str) {
1528
- return escape(str);
1594
+ return escape.call(this, str);
1529
1595
  }
1530
1596
  function unescape(str) {
1531
- return stringify(str).replace(/&(amp|lt|gt|#34|#39);/g, m => unescapeMap[m]);
1597
+ str = stringify(str);
1598
+ this.context.memoryLimit.use(str.length);
1599
+ return str.replace(/&(amp|lt|gt|#34|#39);/g, m => unescapeMap[m]);
1532
1600
  }
1533
1601
  function escape_once(str) {
1534
- return escape(unescape(stringify(str)));
1602
+ return escape.call(this, unescape.call(this, str));
1535
1603
  }
1536
1604
  function newline_to_br(v) {
1537
- return stringify(v).replace(/\r?\n/gm, '<br />\n');
1605
+ const str = stringify(v);
1606
+ this.context.memoryLimit.use(str.length);
1607
+ return str.replace(/\r?\n/gm, '<br />\n');
1538
1608
  }
1539
1609
  function strip_html(v) {
1540
- return stringify(v).replace(/<script[\s\S]*?<\/script>|<style[\s\S]*?<\/style>|<.*?>|<!--[\s\S]*?-->/g, '');
1610
+ const str = stringify(v);
1611
+ this.context.memoryLimit.use(str.length);
1612
+ return str.replace(/<script[\s\S]*?<\/script>|<style[\s\S]*?<\/style>|<.*?>|<!--[\s\S]*?-->/g, '');
1541
1613
  }
1542
1614
 
1543
1615
  var htmlFilters = /*#__PURE__*/Object.freeze({
@@ -1549,18 +1621,68 @@ var htmlFilters = /*#__PURE__*/Object.freeze({
1549
1621
  strip_html: strip_html
1550
1622
  });
1551
1623
 
1624
+ class MapFS {
1625
+ constructor(mapping) {
1626
+ this.mapping = mapping;
1627
+ this.sep = '/';
1628
+ }
1629
+ exists(filepath) {
1630
+ return __awaiter(this, void 0, void 0, function* () {
1631
+ return this.existsSync(filepath);
1632
+ });
1633
+ }
1634
+ existsSync(filepath) {
1635
+ return !isNil(this.mapping[filepath]);
1636
+ }
1637
+ readFile(filepath) {
1638
+ return __awaiter(this, void 0, void 0, function* () {
1639
+ return this.readFileSync(filepath);
1640
+ });
1641
+ }
1642
+ readFileSync(filepath) {
1643
+ const content = this.mapping[filepath];
1644
+ if (isNil(content))
1645
+ throw new Error(`ENOENT: ${filepath}`);
1646
+ return content;
1647
+ }
1648
+ dirname(filepath) {
1649
+ const segments = filepath.split(this.sep);
1650
+ segments.pop();
1651
+ return segments.join(this.sep);
1652
+ }
1653
+ resolve(dir, file, ext) {
1654
+ file += ext;
1655
+ if (dir === '.')
1656
+ return file;
1657
+ const segments = dir.split(/\/+/);
1658
+ for (const segment of file.split(this.sep)) {
1659
+ if (segment === '.' || segment === '')
1660
+ continue;
1661
+ else if (segment === '..') {
1662
+ if (segments.length > 1 || segments[0] !== '')
1663
+ segments.pop();
1664
+ }
1665
+ else
1666
+ segments.push(segment);
1667
+ }
1668
+ return segments.join(this.sep);
1669
+ }
1670
+ }
1671
+
1552
1672
  const defaultOptions = {
1553
1673
  root: ['.'],
1554
1674
  layouts: ['.'],
1555
1675
  partials: ['.'],
1556
1676
  relativeReference: true,
1557
1677
  jekyllInclude: false,
1678
+ keyValueSeparator: ':',
1558
1679
  cache: undefined,
1559
1680
  extname: '',
1560
1681
  fs: fs,
1561
1682
  dynamicPartials: true,
1562
1683
  jsTruthy: false,
1563
1684
  dateFormat: '%A, %B %-e, %Y at %-l:%M %P %z',
1685
+ locale: '',
1564
1686
  trimTagRight: false,
1565
1687
  trimTagLeft: false,
1566
1688
  trimOutputRight: false,
@@ -1577,9 +1699,13 @@ const defaultOptions = {
1577
1699
  lenientIf: false,
1578
1700
  globals: {},
1579
1701
  keepOutputType: false,
1580
- operators: defaultOperators
1702
+ operators: defaultOperators,
1703
+ memoryLimit: Infinity,
1704
+ parseLimit: Infinity,
1705
+ renderLimit: Infinity
1581
1706
  };
1582
1707
  function normalize(options) {
1708
+ var _a, _b;
1583
1709
  if (options.hasOwnProperty('root')) {
1584
1710
  if (!options.hasOwnProperty('partials'))
1585
1711
  options.partials = options.root;
@@ -1605,6 +1731,14 @@ function normalize(options) {
1605
1731
  options.partials = normalizeDirectoryList(options.partials);
1606
1732
  options.layouts = normalizeDirectoryList(options.layouts);
1607
1733
  options.outputEscape = options.outputEscape && getOutputEscapeFunction(options.outputEscape);
1734
+ if (!options.locale) {
1735
+ options.locale = (_b = (_a = getDateTimeFormat()) === null || _a === void 0 ? void 0 : _a().resolvedOptions().locale) !== null && _b !== void 0 ? _b : 'en-US';
1736
+ }
1737
+ if (options.templates) {
1738
+ options.fs = new MapFS(options.templates);
1739
+ options.relativeReference = true;
1740
+ options.root = options.partials = options.layouts = '.';
1741
+ }
1608
1742
  return options;
1609
1743
  }
1610
1744
  function getOutputEscapeFunction(nameOrFunction) {
@@ -1731,9 +1865,7 @@ class Tokenizer {
1731
1865
  this.skipBlank();
1732
1866
  if (this.end())
1733
1867
  return null;
1734
- this.assert(this.peek() === '|', `expected "|" before filter`);
1735
- this.p++;
1736
- const begin = this.p;
1868
+ this.assert(this.read() === '|', `expected "|" before filter`);
1737
1869
  const name = this.readIdentifier();
1738
1870
  if (!name.size()) {
1739
1871
  this.assert(this.end(), `expected filter name`);
@@ -1754,7 +1886,7 @@ class Tokenizer {
1754
1886
  else {
1755
1887
  throw this.error('expected ":" after filter name');
1756
1888
  }
1757
- return new FilterToken(name.getText(), args, this.input, begin, this.p, this.file);
1889
+ return new FilterToken(name.getText(), args, this.input, name.begin, this.p, this.file);
1758
1890
  }
1759
1891
  readFilterArg() {
1760
1892
  const key = this.readValue();
@@ -1795,7 +1927,7 @@ class Tokenizer {
1795
1927
  }
1796
1928
  return new HTMLToken(this.input, begin, this.p, this.file);
1797
1929
  }
1798
- readTagToken(options = defaultOptions) {
1930
+ readTagToken(options) {
1799
1931
  const { file, input } = this;
1800
1932
  const begin = this.p;
1801
1933
  if (this.readToDelimiter(options.tagDelimiterRight) === -1) {
@@ -1926,7 +2058,7 @@ class Tokenizer {
1926
2058
  return;
1927
2059
  let value;
1928
2060
  this.skipBlank();
1929
- const sep = jekyllStyle ? '=' : ':';
2061
+ const sep = isString(jekyllStyle) ? jekyllStyle : (jekyllStyle ? '=' : ':');
1930
2062
  if (this.peek() === sep) {
1931
2063
  ++this.p;
1932
2064
  value = this.readValue();
@@ -1942,6 +2074,9 @@ class Tokenizer {
1942
2074
  end() {
1943
2075
  return this.p >= this.N;
1944
2076
  }
2077
+ read() {
2078
+ return this.input[this.p++];
2079
+ }
1945
2080
  readTo(end) {
1946
2081
  while (this.p < this.N) {
1947
2082
  ++this.p;
@@ -2190,7 +2325,7 @@ function createTagClass(options) {
2190
2325
  }
2191
2326
  }
2192
2327
  *render(ctx, emitter) {
2193
- const hash = (yield new Hash(this.token.args).render(ctx));
2328
+ const hash = (yield new Hash(this.token.args, ctx.opts.keyValueSeparator).render(ctx));
2194
2329
  return yield options.render.call(this, ctx, emitter, hash);
2195
2330
  }
2196
2331
  };
@@ -2201,13 +2336,14 @@ function isKeyValuePair(arr) {
2201
2336
  }
2202
2337
 
2203
2338
  class Filter {
2204
- constructor(name, options, args, liquid) {
2205
- this.name = name;
2339
+ constructor(token, options, liquid) {
2340
+ this.token = token;
2341
+ this.name = token.name;
2206
2342
  this.handler = isFunction(options)
2207
2343
  ? options
2208
2344
  : (isFunction(options === null || options === void 0 ? void 0 : options.handler) ? options.handler : identify);
2209
2345
  this.raw = !isFunction(options) && !!(options === null || options === void 0 ? void 0 : options.raw);
2210
- this.args = args;
2346
+ this.args = token.args;
2211
2347
  this.liquid = liquid;
2212
2348
  }
2213
2349
  *render(value, context) {
@@ -2218,7 +2354,7 @@ class Filter {
2218
2354
  else
2219
2355
  argv.push(yield evalToken(arg, context));
2220
2356
  }
2221
- return yield this.handler.apply({ context, liquid: this.liquid }, [value, ...argv]);
2357
+ return yield this.handler.apply({ context, token: this.token, liquid: this.liquid }, [value, ...argv]);
2222
2358
  }
2223
2359
  }
2224
2360
 
@@ -2232,7 +2368,7 @@ class Value {
2232
2368
  ? new Tokenizer(input, liquid.options.operators).readFilteredValue()
2233
2369
  : input;
2234
2370
  this.initial = token.initial;
2235
- this.filters = token.filters.map(({ name, args }) => new Filter(name, this.getFilter(liquid, name), args, liquid));
2371
+ this.filters = token.filters.map(token => new Filter(token, this.getFilter(liquid, token.name), liquid));
2236
2372
  }
2237
2373
  *value(ctx, lenient) {
2238
2374
  lenient = lenient || (ctx.opts.lenientIf && this.filters.length > 0 && this.filters[0].name === 'default');
@@ -2258,7 +2394,8 @@ class Output extends TemplateImpl {
2258
2394
  const filters = this.value.filters;
2259
2395
  const outputEscape = liquid.options.outputEscape;
2260
2396
  if (!((_a = filters[filters.length - 1]) === null || _a === void 0 ? void 0 : _a.raw) && outputEscape) {
2261
- filters.push(new Filter(toString.call(outputEscape), outputEscape, [], liquid));
2397
+ const token = new FilterToken(toString.call(outputEscape), [], '', 0, 0);
2398
+ filters.push(new Filter(token, outputEscape, liquid));
2262
2399
  }
2263
2400
  }
2264
2401
  *render(ctx, emitter) {
@@ -2293,7 +2430,7 @@ class Loader {
2293
2430
  this.shouldLoadRelative = (referencedFile) => rRelativePath.test(referencedFile);
2294
2431
  }
2295
2432
  else {
2296
- this.shouldLoadRelative = (referencedFile) => false;
2433
+ this.shouldLoadRelative = (_referencedFile) => false;
2297
2434
  }
2298
2435
  this.contains = this.options.fs.contains || (() => true);
2299
2436
  }
@@ -2350,8 +2487,11 @@ class Parser {
2350
2487
  this.fs = this.liquid.options.fs;
2351
2488
  this.parseFile = this.cache ? this._parseFileCached : this._parseFile;
2352
2489
  this.loader = new Loader(this.liquid.options);
2490
+ this.parseLimit = new Limiter('parse length', liquid.options.parseLimit);
2353
2491
  }
2354
2492
  parse(html, filepath) {
2493
+ html = String(html);
2494
+ this.parseLimit.use(html.length);
2355
2495
  const tokenizer = new Tokenizer(html, this.liquid.options.operators, filepath);
2356
2496
  const tokens = tokenizer.readTopLevelTokens(this.liquid.options);
2357
2497
  return this.parseTokens(tokens);
@@ -2359,9 +2499,20 @@ class Parser {
2359
2499
  parseTokens(tokens) {
2360
2500
  let token;
2361
2501
  const templates = [];
2502
+ const errors = [];
2362
2503
  while ((token = tokens.shift())) {
2363
- templates.push(this.parseToken(token, tokens));
2504
+ try {
2505
+ templates.push(this.parseToken(token, tokens));
2506
+ }
2507
+ catch (err) {
2508
+ if (this.liquid.options.catchAllErrors)
2509
+ errors.push(err);
2510
+ else
2511
+ throw err;
2512
+ }
2364
2513
  }
2514
+ if (errors.length)
2515
+ throw new LiquidErrors(errors);
2365
2516
  return templates;
2366
2517
  }
2367
2518
  parseToken(token, remainTokens) {
@@ -2369,7 +2520,7 @@ class Parser {
2369
2520
  if (isTagToken(token)) {
2370
2521
  const TagClass = this.liquid.tags[token.name];
2371
2522
  assert(TagClass, `tag "${token.name}" not found`);
2372
- return new TagClass(token, remainTokens, this.liquid);
2523
+ return new TagClass(token, remainTokens, this.liquid, this);
2373
2524
  }
2374
2525
  if (isOutputToken(token)) {
2375
2526
  return new Output(token, this.liquid);
@@ -2407,7 +2558,7 @@ class Parser {
2407
2558
  }
2408
2559
  *_parseFile(file, sync, type = LookupType.Root, currentFile) {
2409
2560
  const filepath = yield this.loader.lookup(file, type, sync, currentFile);
2410
- return this.liquid.parse(sync ? this.fs.readFileSync(filepath) : yield this.fs.readFile(filepath), filepath);
2561
+ return this.parse(sync ? this.fs.readFileSync(filepath) : yield this.fs.readFile(filepath), filepath);
2411
2562
  }
2412
2563
  }
2413
2564
 
@@ -2482,8 +2633,8 @@ var typeGuards = /*#__PURE__*/Object.freeze({
2482
2633
  });
2483
2634
 
2484
2635
  class Context {
2485
- constructor(env = {}, opts = defaultOptions, renderOptions = {}) {
2486
- var _a, _b, _c;
2636
+ constructor(env = {}, opts = defaultOptions, renderOptions = {}, { memoryLimit, renderLimit } = {}) {
2637
+ var _a, _b, _c, _d, _e;
2487
2638
  /**
2488
2639
  * insert a Context-level empty scope,
2489
2640
  * for tags like `{% capture %}` `{% assign %}` to operate
@@ -2496,6 +2647,8 @@ class Context {
2496
2647
  this.environments = isObject(env) ? env : Object(env);
2497
2648
  this.strictVariables = (_b = renderOptions.strictVariables) !== null && _b !== void 0 ? _b : this.opts.strictVariables;
2498
2649
  this.ownPropertyOnly = (_c = renderOptions.ownPropertyOnly) !== null && _c !== void 0 ? _c : opts.ownPropertyOnly;
2650
+ this.memoryLimit = memoryLimit !== null && memoryLimit !== void 0 ? memoryLimit : new Limiter('memory alloc', (_d = renderOptions.memoryLimit) !== null && _d !== void 0 ? _d : opts.memoryLimit);
2651
+ this.renderLimit = renderLimit !== null && renderLimit !== void 0 ? renderLimit : new Limiter('template render', getPerformance().now() + ((_e = renderOptions.renderLimit) !== null && _e !== void 0 ? _e : opts.renderLimit));
2499
2652
  }
2500
2653
  getRegister(key) {
2501
2654
  return (this.registers[key] = this.registers[key] || {});
@@ -2552,6 +2705,16 @@ class Context {
2552
2705
  bottom() {
2553
2706
  return this.scopes[0];
2554
2707
  }
2708
+ spawn(scope = {}) {
2709
+ return new Context(scope, this.opts, {
2710
+ sync: this.sync,
2711
+ globals: this.globals,
2712
+ strictVariables: this.strictVariables
2713
+ }, {
2714
+ renderLimit: this.renderLimit,
2715
+ memoryLimit: this.memoryLimit
2716
+ });
2717
+ }
2555
2718
  findScope(key) {
2556
2719
  for (let i = this.scopes.length - 1; i >= 0; i--) {
2557
2720
  const candidate = this.scopes[i];
@@ -2583,7 +2746,7 @@ function readProperty(obj, key, ownPropertyOnly) {
2583
2746
  return value;
2584
2747
  }
2585
2748
  function readJSProperty(obj, key, ownPropertyOnly) {
2586
- if (ownPropertyOnly && !Object.hasOwnProperty.call(obj, key) && !(obj instanceof Drop))
2749
+ if (ownPropertyOnly && !hasOwnProperty.call(obj, key) && !(obj instanceof Drop))
2587
2750
  return undefined;
2588
2751
  return obj[key];
2589
2752
  }
@@ -2598,7 +2761,7 @@ function readLast(obj) {
2598
2761
  return obj['last'];
2599
2762
  }
2600
2763
  function readSize(obj) {
2601
- if (obj.hasOwnProperty('size') || obj['size'] !== undefined)
2764
+ if (hasOwnProperty.call(obj, 'size') || obj['size'] !== undefined)
2602
2765
  return obj['size'];
2603
2766
  if (isArray(obj) || isString(obj))
2604
2767
  return obj.length;
@@ -2705,13 +2868,25 @@ var urlFilters = /*#__PURE__*/Object.freeze({
2705
2868
  slugify: slugify
2706
2869
  });
2707
2870
 
2708
- const join = argumentsToValue((v, arg) => toArray(v).join(arg === undefined ? ' ' : arg));
2871
+ const join = argumentsToValue(function (v, arg) {
2872
+ const array = toArray(v);
2873
+ const sep = isNil(arg) ? ' ' : stringify(arg);
2874
+ const complexity = array.length * (1 + sep.length);
2875
+ this.context.memoryLimit.use(complexity);
2876
+ return array.join(sep);
2877
+ });
2709
2878
  const last$1 = argumentsToValue((v) => isArray(v) ? last(v) : '');
2710
2879
  const first = argumentsToValue((v) => isArray(v) ? v[0] : '');
2711
- const reverse = argumentsToValue((v) => [...toArray(v)].reverse());
2880
+ const reverse = argumentsToValue(function (v) {
2881
+ const array = toArray(v);
2882
+ this.context.memoryLimit.use(array.length);
2883
+ return [...array].reverse();
2884
+ });
2712
2885
  function* sort(arr, property) {
2713
2886
  const values = [];
2714
- for (const item of toArray(arr)) {
2887
+ const array = toArray(arr);
2888
+ this.context.memoryLimit.use(array.length);
2889
+ for (const item of array) {
2715
2890
  values.push([
2716
2891
  item,
2717
2892
  property ? yield this.context._getFromScope(item, stringify(property).split('.'), false) : item
@@ -2728,35 +2903,47 @@ function sort_natural(input, property) {
2728
2903
  const compare = property === undefined
2729
2904
  ? caseInsensitiveCompare
2730
2905
  : (lhs, rhs) => caseInsensitiveCompare(lhs[propertyString], rhs[propertyString]);
2731
- return [...toArray(input)].sort(compare);
2906
+ const array = toArray(input);
2907
+ this.context.memoryLimit.use(array.length);
2908
+ return [...array].sort(compare);
2732
2909
  }
2733
2910
  const size = (v) => (v && v.length) || 0;
2734
2911
  function* map(arr, property) {
2735
2912
  const results = [];
2736
- for (const item of toArray(arr)) {
2913
+ const array = toArray(arr);
2914
+ this.context.memoryLimit.use(array.length);
2915
+ for (const item of array) {
2737
2916
  results.push(yield this.context._getFromScope(item, stringify(property), false));
2738
2917
  }
2739
2918
  return results;
2740
2919
  }
2741
2920
  function* sum(arr, property) {
2742
2921
  let sum = 0;
2743
- for (const item of toArray(arr)) {
2922
+ const array = toArray(arr);
2923
+ for (const item of array) {
2744
2924
  const data = Number(property ? yield this.context._getFromScope(item, stringify(property), false) : item);
2745
2925
  sum += Number.isNaN(data) ? 0 : data;
2746
2926
  }
2747
2927
  return sum;
2748
2928
  }
2749
2929
  function compact(arr) {
2750
- return toArray(arr).filter(x => !isNil(toValue(x)));
2930
+ const array = toArray(arr);
2931
+ this.context.memoryLimit.use(array.length);
2932
+ return array.filter(x => !isNil(toValue(x)));
2751
2933
  }
2752
2934
  function concat(v, arg = []) {
2753
- return toArray(v).concat(toArray(arg));
2935
+ const lhs = toArray(v);
2936
+ const rhs = toArray(arg);
2937
+ this.context.memoryLimit.use(lhs.length + rhs.length);
2938
+ return lhs.concat(rhs);
2754
2939
  }
2755
2940
  function push(v, arg) {
2756
- return concat(v, [arg]);
2941
+ return concat.call(this, v, [arg]);
2757
2942
  }
2758
2943
  function unshift(v, arg) {
2759
- const clone = [...toArray(v)];
2944
+ const array = toArray(v);
2945
+ this.context.memoryLimit.use(array.length);
2946
+ const clone = [...array];
2760
2947
  clone.unshift(arg);
2761
2948
  return clone;
2762
2949
  }
@@ -2766,7 +2953,9 @@ function pop(v) {
2766
2953
  return clone;
2767
2954
  }
2768
2955
  function shift(v) {
2769
- const clone = [...toArray(v)];
2956
+ const array = toArray(v);
2957
+ this.context.memoryLimit.use(array.length);
2958
+ const clone = [...array];
2770
2959
  clone.shift();
2771
2960
  return clone;
2772
2961
  }
@@ -2777,14 +2966,16 @@ function slice(v, begin, length = 1) {
2777
2966
  if (!isArray(v))
2778
2967
  v = stringify(v);
2779
2968
  begin = begin < 0 ? v.length + begin : begin;
2969
+ this.context.memoryLimit.use(length);
2780
2970
  return v.slice(begin, begin + length);
2781
2971
  }
2782
2972
  function* where(arr, property, expected) {
2783
2973
  const values = [];
2784
2974
  arr = toArray(arr);
2975
+ this.context.memoryLimit.use(arr.length);
2785
2976
  const token = new Tokenizer(stringify(property)).readScopeValue();
2786
2977
  for (const item of arr) {
2787
- values.push(yield evalToken(token, new Context(item)));
2978
+ values.push(yield evalToken(token, this.context.spawn(item)));
2788
2979
  }
2789
2980
  return arr.filter((_, i) => {
2790
2981
  if (expected === undefined)
@@ -2795,8 +2986,10 @@ function* where(arr, property, expected) {
2795
2986
  function* where_exp(arr, itemName, exp) {
2796
2987
  const filtered = [];
2797
2988
  const keyTemplate = new Value(stringify(exp), this.liquid);
2798
- for (const item of toArray(arr)) {
2799
- const value = yield keyTemplate.value(new Context({ [itemName]: item }));
2989
+ const array = toArray(arr);
2990
+ this.context.memoryLimit.use(array.length);
2991
+ for (const item of array) {
2992
+ const value = yield keyTemplate.value(this.context.spawn({ [itemName]: item }));
2800
2993
  if (value)
2801
2994
  filtered.push(item);
2802
2995
  }
@@ -2806,8 +2999,9 @@ function* group_by(arr, property) {
2806
2999
  const map = new Map();
2807
3000
  arr = toArray(arr);
2808
3001
  const token = new Tokenizer(stringify(property)).readScopeValue();
3002
+ this.context.memoryLimit.use(arr.length);
2809
3003
  for (const item of arr) {
2810
- const key = yield evalToken(token, new Context(item));
3004
+ const key = yield evalToken(token, this.context.spawn(item));
2811
3005
  if (!map.has(key))
2812
3006
  map.set(key, []);
2813
3007
  map.get(key).push(item);
@@ -2817,8 +3011,10 @@ function* group_by(arr, property) {
2817
3011
  function* group_by_exp(arr, itemName, exp) {
2818
3012
  const map = new Map();
2819
3013
  const keyTemplate = new Value(stringify(exp), this.liquid);
2820
- for (const item of toArray(arr)) {
2821
- const key = yield keyTemplate.value(new Context({ [itemName]: item }));
3014
+ arr = toArray(arr);
3015
+ this.context.memoryLimit.use(arr.length);
3016
+ for (const item of arr) {
3017
+ const key = yield keyTemplate.value(this.context.spawn({ [itemName]: item }));
2822
3018
  if (!map.has(key))
2823
3019
  map.set(key, []);
2824
3020
  map.get(key).push(item);
@@ -2827,31 +3023,26 @@ function* group_by_exp(arr, itemName, exp) {
2827
3023
  }
2828
3024
  function* find(arr, property, expected) {
2829
3025
  const token = new Tokenizer(stringify(property)).readScopeValue();
2830
- for (const item of toArray(arr)) {
2831
- const value = yield evalToken(token, new Context(item));
3026
+ const array = toArray(arr);
3027
+ for (const item of array) {
3028
+ const value = yield evalToken(token, this.context.spawn(item));
2832
3029
  if (equals(value, expected))
2833
3030
  return item;
2834
3031
  }
2835
- return null;
2836
3032
  }
2837
3033
  function* find_exp(arr, itemName, exp) {
2838
3034
  const predicate = new Value(stringify(exp), this.liquid);
2839
- for (const item of toArray(arr)) {
2840
- const value = yield predicate.value(new Context({ [itemName]: item }));
3035
+ const array = toArray(arr);
3036
+ for (const item of array) {
3037
+ const value = yield predicate.value(this.context.spawn({ [itemName]: item }));
2841
3038
  if (value)
2842
3039
  return item;
2843
3040
  }
2844
- return null;
2845
3041
  }
2846
3042
  function uniq(arr) {
2847
- arr = toValue(arr);
2848
- const u = {};
2849
- return (arr || []).filter(val => {
2850
- if (hasOwnProperty.call(u, String(val)))
2851
- return false;
2852
- u[String(val)] = true;
2853
- return true;
2854
- });
3043
+ arr = toArray(arr);
3044
+ this.context.memoryLimit.use(arr.length);
3045
+ return [...new Set(arr)];
2855
3046
  }
2856
3047
  function sample(v, count = 1) {
2857
3048
  v = toValue(v);
@@ -2859,6 +3050,7 @@ function sample(v, count = 1) {
2859
3050
  return [];
2860
3051
  if (!isArray(v))
2861
3052
  v = stringify(v);
3053
+ this.context.memoryLimit.use(count);
2862
3054
  const shuffled = [...v].sort(() => Math.random() - 0.5);
2863
3055
  if (count === 1)
2864
3056
  return shuffled[0];
@@ -2894,6 +3086,9 @@ var arrayFilters = /*#__PURE__*/Object.freeze({
2894
3086
  });
2895
3087
 
2896
3088
  function date(v, format, timezoneOffset) {
3089
+ var _a, _b, _c;
3090
+ 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);
3091
+ this.context.memoryLimit.use(size);
2897
3092
  const date = parseDate(v, this.context.opts, timezoneOffset);
2898
3093
  if (!date)
2899
3094
  return v;
@@ -2927,39 +3122,30 @@ function stringify_date(v, month_type, type, style) {
2927
3122
  }
2928
3123
  function parseDate(v, opts, timezoneOffset) {
2929
3124
  let date;
3125
+ const defaultTimezoneOffset = timezoneOffset !== null && timezoneOffset !== void 0 ? timezoneOffset : opts.timezoneOffset;
3126
+ const locale = opts.locale;
2930
3127
  v = toValue(v);
2931
3128
  if (v === 'now' || v === 'today') {
2932
- date = new Date();
3129
+ date = new LiquidDate(Date.now(), locale, defaultTimezoneOffset);
2933
3130
  }
2934
3131
  else if (isNumber(v)) {
2935
- date = new Date(v * 1000);
3132
+ date = new LiquidDate(v * 1000, locale, defaultTimezoneOffset);
2936
3133
  }
2937
3134
  else if (isString(v)) {
2938
3135
  if (/^\d+$/.test(v)) {
2939
- date = new Date(+v * 1000);
3136
+ date = new LiquidDate(+v * 1000, locale, defaultTimezoneOffset);
2940
3137
  }
2941
- else if (opts.preserveTimezones) {
2942
- date = TimezoneDate.createDateFixedToTimezone(v);
3138
+ else if (opts.preserveTimezones && timezoneOffset === undefined) {
3139
+ date = LiquidDate.createDateFixedToTimezone(v, locale);
2943
3140
  }
2944
3141
  else {
2945
- date = new Date(v);
3142
+ date = new LiquidDate(v, locale, defaultTimezoneOffset);
2946
3143
  }
2947
3144
  }
2948
3145
  else {
2949
- date = v;
2950
- }
2951
- if (!isValidDate(date))
2952
- return;
2953
- if (timezoneOffset !== undefined) {
2954
- date = new TimezoneDate(date, timezoneOffset);
2955
- }
2956
- else if (!(date instanceof TimezoneDate) && opts.timezoneOffset !== undefined) {
2957
- date = new TimezoneDate(date, opts.timezoneOffset);
3146
+ date = new LiquidDate(v, locale, defaultTimezoneOffset);
2958
3147
  }
2959
- return date;
2960
- }
2961
- function isValidDate(date) {
2962
- return (date instanceof Date || date instanceof TimezoneDate) && !isNaN(date.getTime());
3148
+ return date.valid() ? date : undefined;
2963
3149
  }
2964
3150
 
2965
3151
  var dateFilters = /*#__PURE__*/Object.freeze({
@@ -2981,33 +3167,50 @@ const rCJKWord = /[\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF\u3040-\u309F\u30A0-\u
2981
3167
  const rNonCJKWord = /[^\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF\s]+/gu;
2982
3168
  function append(v, arg) {
2983
3169
  assert(arguments.length === 2, 'append expect 2 arguments');
2984
- return stringify(v) + stringify(arg);
3170
+ const lhs = stringify(v);
3171
+ const rhs = stringify(arg);
3172
+ this.context.memoryLimit.use(lhs.length + rhs.length);
3173
+ return lhs + rhs;
2985
3174
  }
2986
3175
  function prepend(v, arg) {
2987
3176
  assert(arguments.length === 2, 'prepend expect 2 arguments');
2988
- return stringify(arg) + stringify(v);
3177
+ const lhs = stringify(v);
3178
+ const rhs = stringify(arg);
3179
+ this.context.memoryLimit.use(lhs.length + rhs.length);
3180
+ return rhs + lhs;
2989
3181
  }
2990
3182
  function lstrip(v, chars) {
3183
+ const str = stringify(v);
3184
+ this.context.memoryLimit.use(str.length);
2991
3185
  if (chars) {
2992
3186
  chars = escapeRegExp(stringify(chars));
2993
- return stringify(v).replace(new RegExp(`^[${chars}]+`, 'g'), '');
3187
+ return str.replace(new RegExp(`^[${chars}]+`, 'g'), '');
2994
3188
  }
2995
- return stringify(v).replace(/^\s+/, '');
3189
+ return str.replace(/^\s+/, '');
2996
3190
  }
2997
3191
  function downcase(v) {
2998
- return stringify(v).toLowerCase();
3192
+ const str = stringify(v);
3193
+ this.context.memoryLimit.use(str.length);
3194
+ return str.toLowerCase();
2999
3195
  }
3000
- function upcase(str) {
3196
+ function upcase(v) {
3197
+ const str = stringify(v);
3198
+ this.context.memoryLimit.use(str.length);
3001
3199
  return stringify(str).toUpperCase();
3002
3200
  }
3003
3201
  function remove(v, arg) {
3004
- return stringify(v).split(stringify(arg)).join('');
3202
+ const str = stringify(v);
3203
+ this.context.memoryLimit.use(str.length);
3204
+ return str.split(stringify(arg)).join('');
3005
3205
  }
3006
3206
  function remove_first(v, l) {
3007
- return stringify(v).replace(stringify(l), '');
3207
+ const str = stringify(v);
3208
+ this.context.memoryLimit.use(str.length);
3209
+ return str.replace(stringify(l), '');
3008
3210
  }
3009
3211
  function remove_last(v, l) {
3010
3212
  const str = stringify(v);
3213
+ this.context.memoryLimit.use(str.length);
3011
3214
  const pattern = stringify(l);
3012
3215
  const index = str.lastIndexOf(pattern);
3013
3216
  if (index === -1)
@@ -3015,14 +3218,18 @@ function remove_last(v, l) {
3015
3218
  return str.substring(0, index) + str.substring(index + pattern.length);
3016
3219
  }
3017
3220
  function rstrip(str, chars) {
3221
+ str = stringify(str);
3222
+ this.context.memoryLimit.use(str.length);
3018
3223
  if (chars) {
3019
3224
  chars = escapeRegExp(stringify(chars));
3020
- return stringify(str).replace(new RegExp(`[${chars}]+$`, 'g'), '');
3225
+ return str.replace(new RegExp(`[${chars}]+$`, 'g'), '');
3021
3226
  }
3022
- return stringify(str).replace(/\s+$/, '');
3227
+ return str.replace(/\s+$/, '');
3023
3228
  }
3024
3229
  function split(v, arg) {
3025
- const arr = stringify(v).split(stringify(arg));
3230
+ const str = stringify(v);
3231
+ this.context.memoryLimit.use(str.length);
3232
+ const arr = str.split(stringify(arg));
3026
3233
  // align to ruby split, which is the behavior of shopify/liquid
3027
3234
  // see: https://ruby-doc.org/core-2.4.0/String.html#method-i-split
3028
3235
  while (arr.length && arr[arr.length - 1] === '')
@@ -3030,29 +3237,39 @@ function split(v, arg) {
3030
3237
  return arr;
3031
3238
  }
3032
3239
  function strip(v, chars) {
3240
+ const str = stringify(v);
3241
+ this.context.memoryLimit.use(str.length);
3033
3242
  if (chars) {
3034
3243
  chars = escapeRegExp(stringify(chars));
3035
- return stringify(v)
3244
+ return str
3036
3245
  .replace(new RegExp(`^[${chars}]+`, 'g'), '')
3037
3246
  .replace(new RegExp(`[${chars}]+$`, 'g'), '');
3038
3247
  }
3039
- return stringify(v).trim();
3248
+ return str.trim();
3040
3249
  }
3041
3250
  function strip_newlines(v) {
3042
- return stringify(v).replace(/\r?\n/gm, '');
3251
+ const str = stringify(v);
3252
+ this.context.memoryLimit.use(str.length);
3253
+ return str.replace(/\r?\n/gm, '');
3043
3254
  }
3044
3255
  function capitalize(str) {
3045
3256
  str = stringify(str);
3257
+ this.context.memoryLimit.use(str.length);
3046
3258
  return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
3047
3259
  }
3048
3260
  function replace(v, pattern, replacement) {
3049
- return stringify(v).split(stringify(pattern)).join(replacement);
3261
+ const str = stringify(v);
3262
+ this.context.memoryLimit.use(str.length);
3263
+ return str.split(stringify(pattern)).join(replacement);
3050
3264
  }
3051
3265
  function replace_first(v, arg1, arg2) {
3052
- return stringify(v).replace(stringify(arg1), arg2);
3266
+ const str = stringify(v);
3267
+ this.context.memoryLimit.use(str.length);
3268
+ return str.replace(stringify(arg1), arg2);
3053
3269
  }
3054
3270
  function replace_last(v, arg1, arg2) {
3055
3271
  const str = stringify(v);
3272
+ this.context.memoryLimit.use(str.length);
3056
3273
  const pattern = stringify(arg1);
3057
3274
  const index = str.lastIndexOf(pattern);
3058
3275
  if (index === -1)
@@ -3061,13 +3278,16 @@ function replace_last(v, arg1, arg2) {
3061
3278
  return str.substring(0, index) + replacement + str.substring(index + pattern.length);
3062
3279
  }
3063
3280
  function truncate(v, l = 50, o = '...') {
3064
- v = stringify(v);
3065
- if (v.length <= l)
3281
+ const str = stringify(v);
3282
+ this.context.memoryLimit.use(str.length);
3283
+ if (str.length <= l)
3066
3284
  return v;
3067
- return v.substring(0, l - o.length) + o;
3285
+ return str.substring(0, l - o.length) + o;
3068
3286
  }
3069
3287
  function truncatewords(v, words = 15, o = '...') {
3070
- const arr = stringify(v).split(/\s+/);
3288
+ const str = stringify(v);
3289
+ this.context.memoryLimit.use(str.length);
3290
+ const arr = str.split(/\s+/);
3071
3291
  if (words <= 0)
3072
3292
  words = 1;
3073
3293
  let ret = arr.slice(0, words).join(' ');
@@ -3076,11 +3296,14 @@ function truncatewords(v, words = 15, o = '...') {
3076
3296
  return ret;
3077
3297
  }
3078
3298
  function normalize_whitespace(v) {
3079
- v = stringify(v);
3080
- return v.replace(/\s+/g, ' ');
3299
+ const str = stringify(v);
3300
+ this.context.memoryLimit.use(str.length);
3301
+ return str.replace(/\s+/g, ' ');
3081
3302
  }
3082
3303
  function number_of_words(input, mode) {
3083
- input = stringify(input).trim();
3304
+ const str = stringify(input);
3305
+ this.context.memoryLimit.use(str.length);
3306
+ input = str.trim();
3084
3307
  if (!input)
3085
3308
  return 0;
3086
3309
  switch (mode) {
@@ -3098,6 +3321,7 @@ function number_of_words(input, mode) {
3098
3321
  }
3099
3322
  }
3100
3323
  function array_to_sentence_string(array, connector = 'and') {
3324
+ this.context.memoryLimit.use(array.length);
3101
3325
  switch (array.length) {
3102
3326
  case 0:
3103
3327
  return '';
@@ -3154,7 +3378,7 @@ class AssignTag extends Tag {
3154
3378
 
3155
3379
  const MODIFIERS = ['offset', 'limit', 'reversed'];
3156
3380
  class ForTag extends Tag {
3157
- constructor(token, remainTokens, liquid) {
3381
+ constructor(token, remainTokens, liquid, parser) {
3158
3382
  super(token, remainTokens, liquid);
3159
3383
  const variable = this.tokenizer.readIdentifier();
3160
3384
  const inStr = this.tokenizer.readIdentifier();
@@ -3164,18 +3388,16 @@ class ForTag extends Tag {
3164
3388
  }
3165
3389
  this.variable = variable.content;
3166
3390
  this.collection = collection;
3167
- this.hash = new Hash(this.tokenizer.remaining());
3391
+ this.hash = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
3168
3392
  this.templates = [];
3169
3393
  this.elseTemplates = [];
3170
3394
  let p;
3171
- const stream = this.liquid.parser.parseStream(remainTokens)
3395
+ const stream = parser.parseStream(remainTokens)
3172
3396
  .on('start', () => (p = this.templates))
3173
- .on('tag:else', () => (p = this.elseTemplates))
3174
- .on('tag:endfor', () => stream.stop())
3397
+ .on('tag:else', tag => { assertEmpty(tag.args); p = this.elseTemplates; })
3398
+ .on('tag:endfor', tag => { assertEmpty(tag.args); stream.stop(); })
3175
3399
  .on('template', (tpl) => p.push(tpl))
3176
- .on('end', () => {
3177
- throw new Error(`tag ${token.getText()} not closed`);
3178
- });
3400
+ .on('end', () => { throw new Error(`tag ${token.getText()} not closed`); });
3179
3401
  stream.start();
3180
3402
  }
3181
3403
  *render(ctx, emitter) {
@@ -3226,7 +3448,7 @@ function limit(arr, count) {
3226
3448
  }
3227
3449
 
3228
3450
  class CaptureTag extends Tag {
3229
- constructor(tagToken, remainTokens, liquid) {
3451
+ constructor(tagToken, remainTokens, liquid, parser) {
3230
3452
  super(tagToken, remainTokens, liquid);
3231
3453
  this.templates = [];
3232
3454
  this.variable = this.readVariableName();
@@ -3234,7 +3456,7 @@ class CaptureTag extends Tag {
3234
3456
  const token = remainTokens.shift();
3235
3457
  if (isTagToken(token) && token.name === 'endcapture')
3236
3458
  return;
3237
- this.templates.push(liquid.parser.parseToken(token, remainTokens));
3459
+ this.templates.push(parser.parseToken(token, remainTokens));
3238
3460
  }
3239
3461
  throw new Error(`tag ${tagToken.getText()} not closed`);
3240
3462
  }
@@ -3255,7 +3477,7 @@ class CaptureTag extends Tag {
3255
3477
  }
3256
3478
 
3257
3479
  class CaseTag extends Tag {
3258
- constructor(tagToken, remainTokens, liquid) {
3480
+ constructor(tagToken, remainTokens, liquid, parser) {
3259
3481
  super(tagToken, remainTokens, liquid);
3260
3482
  this.branches = [];
3261
3483
  this.elseTemplates = [];
@@ -3263,7 +3485,7 @@ class CaseTag extends Tag {
3263
3485
  this.elseTemplates = [];
3264
3486
  let p = [];
3265
3487
  let elseCount = 0;
3266
- const stream = this.liquid.parser.parseStream(remainTokens)
3488
+ const stream = parser.parseStream(remainTokens)
3267
3489
  .on('tag:when', (token) => {
3268
3490
  if (elseCount > 0) {
3269
3491
  return;
@@ -3334,10 +3556,10 @@ class CommentTag extends Tag {
3334
3556
  }
3335
3557
 
3336
3558
  class RenderTag extends Tag {
3337
- constructor(token, remainTokens, liquid) {
3559
+ constructor(token, remainTokens, liquid, parser) {
3338
3560
  super(token, remainTokens, liquid);
3339
3561
  const tokenizer = this.tokenizer;
3340
- this.file = parseFilePath(tokenizer, this.liquid);
3562
+ this.file = parseFilePath(tokenizer, this.liquid, parser);
3341
3563
  this.currentFile = token.file;
3342
3564
  while (!tokenizer.end()) {
3343
3565
  tokenizer.skipBlank();
@@ -3371,13 +3593,13 @@ class RenderTag extends Tag {
3371
3593
  tokenizer.p = begin;
3372
3594
  break;
3373
3595
  }
3374
- this.hash = new Hash(tokenizer.remaining());
3596
+ this.hash = new Hash(tokenizer.remaining(), liquid.options.keyValueSeparator);
3375
3597
  }
3376
3598
  *render(ctx, emitter) {
3377
3599
  const { liquid, hash } = this;
3378
3600
  const filepath = (yield renderFilePath(this['file'], ctx, liquid));
3379
3601
  assert(filepath, () => `illegal file path "${filepath}"`);
3380
- const childCtx = new Context({}, ctx.opts, { sync: ctx.sync, globals: ctx.globals, strictVariables: ctx.strictVariables });
3602
+ const childCtx = ctx.spawn();
3381
3603
  const scope = childCtx.bottom();
3382
3604
  __assign(scope, yield hash.render(ctx));
3383
3605
  if (this['with']) {
@@ -3407,7 +3629,7 @@ class RenderTag extends Tag {
3407
3629
  * @return Token for expression (not quoted)
3408
3630
  * @throws TypeError if cannot read next token
3409
3631
  */
3410
- function parseFilePath(tokenizer, liquid) {
3632
+ function parseFilePath(tokenizer, liquid, parser) {
3411
3633
  if (liquid.options.dynamicPartials) {
3412
3634
  const file = tokenizer.readValue();
3413
3635
  tokenizer.assert(file, 'illegal file path');
@@ -3415,13 +3637,13 @@ function parseFilePath(tokenizer, liquid) {
3415
3637
  return;
3416
3638
  if (isQuotedToken(file)) {
3417
3639
  // for filenames like "files/{{file}}", eval as liquid template
3418
- const templates = liquid.parse(evalQuotedToken(file));
3640
+ const templates = parser.parse(evalQuotedToken(file));
3419
3641
  return optimize(templates);
3420
3642
  }
3421
3643
  return file;
3422
3644
  }
3423
3645
  const tokens = [...tokenizer.readFileNameTemplate(liquid.options)];
3424
- const templates = optimize(liquid.parser.parseTokens(tokens));
3646
+ const templates = optimize(parser.parseTokens(tokens));
3425
3647
  return templates === 'none' ? undefined : templates;
3426
3648
  }
3427
3649
  function optimize(templates) {
@@ -3439,10 +3661,10 @@ function* renderFilePath(file, ctx, liquid) {
3439
3661
  }
3440
3662
 
3441
3663
  class IncludeTag extends Tag {
3442
- constructor(token, remainTokens, liquid) {
3664
+ constructor(token, remainTokens, liquid, parser) {
3443
3665
  super(token, remainTokens, liquid);
3444
3666
  const { tokenizer } = token;
3445
- this['file'] = parseFilePath(tokenizer, this.liquid);
3667
+ this['file'] = parseFilePath(tokenizer, this.liquid, parser);
3446
3668
  this['currentFile'] = token.file;
3447
3669
  const begin = tokenizer.p;
3448
3670
  const withStr = tokenizer.readIdentifier();
@@ -3456,7 +3678,7 @@ class IncludeTag extends Tag {
3456
3678
  }
3457
3679
  else
3458
3680
  tokenizer.p = begin;
3459
- this.hash = new Hash(tokenizer.remaining(), this.liquid.options.jekyllInclude);
3681
+ this.hash = new Hash(tokenizer.remaining(), liquid.options.jekyllInclude || liquid.options.keyValueSeparator);
3460
3682
  }
3461
3683
  *render(ctx, emitter) {
3462
3684
  const { liquid, hash, withVar } = this;
@@ -3529,37 +3751,29 @@ class CycleTag extends Tag {
3529
3751
  }
3530
3752
 
3531
3753
  class IfTag extends Tag {
3532
- constructor(tagToken, remainTokens, liquid) {
3754
+ constructor(tagToken, remainTokens, liquid, parser) {
3533
3755
  super(tagToken, remainTokens, liquid);
3534
3756
  this.branches = [];
3535
- this.elseTemplates = [];
3536
3757
  let p = [];
3537
- let elseCount = 0;
3538
- liquid.parser.parseStream(remainTokens)
3758
+ parser.parseStream(remainTokens)
3539
3759
  .on('start', () => this.branches.push({
3540
3760
  value: new Value(tagToken.args, this.liquid),
3541
3761
  templates: (p = [])
3542
3762
  }))
3543
3763
  .on('tag:elsif', (token) => {
3544
- if (elseCount > 0) {
3545
- p = [];
3546
- return;
3547
- }
3764
+ assert(!this.elseTemplates, 'unexpected elsif after else');
3548
3765
  this.branches.push({
3549
3766
  value: new Value(token.args, this.liquid),
3550
3767
  templates: (p = [])
3551
3768
  });
3552
3769
  })
3553
- .on('tag:else', () => {
3554
- elseCount++;
3555
- p = this.elseTemplates;
3556
- })
3557
- .on('tag:endif', function () { this.stop(); })
3558
- .on('template', (tpl) => {
3559
- if (p !== this.elseTemplates || elseCount === 1) {
3560
- p.push(tpl);
3561
- }
3770
+ .on('tag:else', tag => {
3771
+ assertEmpty(tag.args);
3772
+ assert(!this.elseTemplates, 'duplicated else');
3773
+ p = this.elseTemplates = [];
3562
3774
  })
3775
+ .on('tag:endif', function (tag) { assertEmpty(tag.args); this.stop(); })
3776
+ .on('template', (tpl) => p.push(tpl))
3563
3777
  .on('end', () => { throw new Error(`tag ${tagToken.getText()} not closed`); })
3564
3778
  .start();
3565
3779
  }
@@ -3572,7 +3786,7 @@ class IfTag extends Tag {
3572
3786
  return;
3573
3787
  }
3574
3788
  }
3575
- yield r.renderTemplates(this.elseTemplates, ctx, emitter);
3789
+ yield r.renderTemplates(this.elseTemplates || [], ctx, emitter);
3576
3790
  }
3577
3791
  }
3578
3792
 
@@ -3593,12 +3807,12 @@ class IncrementTag extends Tag {
3593
3807
  }
3594
3808
 
3595
3809
  class LayoutTag extends Tag {
3596
- constructor(token, remainTokens, liquid) {
3810
+ constructor(token, remainTokens, liquid, parser) {
3597
3811
  super(token, remainTokens, liquid);
3598
- this.file = parseFilePath(this.tokenizer, this.liquid);
3812
+ this.file = parseFilePath(this.tokenizer, this.liquid, parser);
3599
3813
  this['currentFile'] = token.file;
3600
- this.args = new Hash(this.tokenizer.remaining());
3601
- this.templates = this.liquid.parser.parseTokens(remainTokens);
3814
+ this.args = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
3815
+ this.templates = parser.parseTokens(remainTokens);
3602
3816
  }
3603
3817
  *render(ctx, emitter) {
3604
3818
  const { liquid, args, file } = this;
@@ -3627,7 +3841,7 @@ class LayoutTag extends Tag {
3627
3841
  }
3628
3842
 
3629
3843
  class BlockTag extends Tag {
3630
- constructor(token, remainTokens, liquid) {
3844
+ constructor(token, remainTokens, liquid, parser) {
3631
3845
  super(token, remainTokens, liquid);
3632
3846
  this.templates = [];
3633
3847
  const match = /\w+/.exec(token.args);
@@ -3636,7 +3850,7 @@ class BlockTag extends Tag {
3636
3850
  const token = remainTokens.shift();
3637
3851
  if (isTagToken(token) && token.name === 'endblock')
3638
3852
  return;
3639
- const template = liquid.parser.parseToken(token, remainTokens);
3853
+ const template = parser.parseToken(token, remainTokens);
3640
3854
  this.templates.push(template);
3641
3855
  }
3642
3856
  throw new Error(`tag ${token.getText()} not closed`);
@@ -3706,7 +3920,7 @@ class TablerowloopDrop extends ForloopDrop {
3706
3920
  }
3707
3921
 
3708
3922
  class TablerowTag extends Tag {
3709
- constructor(tagToken, remainTokens, liquid) {
3923
+ constructor(tagToken, remainTokens, liquid, parser) {
3710
3924
  super(tagToken, remainTokens, liquid);
3711
3925
  const variable = this.tokenizer.readIdentifier();
3712
3926
  this.tokenizer.skipBlank();
@@ -3717,10 +3931,10 @@ class TablerowTag extends Tag {
3717
3931
  }
3718
3932
  this.variable = variable.content;
3719
3933
  this.collection = collectionToken;
3720
- this.args = new Hash(this.tokenizer.remaining());
3934
+ this.args = new Hash(this.tokenizer.remaining(), liquid.options.keyValueSeparator);
3721
3935
  this.templates = [];
3722
3936
  let p;
3723
- const stream = this.liquid.parser.parseStream(remainTokens)
3937
+ const stream = parser.parseStream(remainTokens)
3724
3938
  .on('start', () => (p = this.templates))
3725
3939
  .on('tag:endtablerow', () => stream.stop())
3726
3940
  .on('template', (tpl) => p.push(tpl))
@@ -3758,13 +3972,13 @@ class TablerowTag extends Tag {
3758
3972
  }
3759
3973
 
3760
3974
  class UnlessTag extends Tag {
3761
- constructor(tagToken, remainTokens, liquid) {
3975
+ constructor(tagToken, remainTokens, liquid, parser) {
3762
3976
  super(tagToken, remainTokens, liquid);
3763
3977
  this.branches = [];
3764
3978
  this.elseTemplates = [];
3765
3979
  let p = [];
3766
3980
  let elseCount = 0;
3767
- this.liquid.parser.parseStream(remainTokens)
3981
+ parser.parseStream(remainTokens)
3768
3982
  .on('start', () => this.branches.push({
3769
3983
  value: new Value(tagToken.args, this.liquid),
3770
3984
  test: isFalsy,
@@ -3836,10 +4050,10 @@ class EchoTag extends Tag {
3836
4050
  }
3837
4051
 
3838
4052
  class LiquidTag extends Tag {
3839
- constructor(token, remainTokens, liquid) {
4053
+ constructor(token, remainTokens, liquid, parser) {
3840
4054
  super(token, remainTokens, liquid);
3841
4055
  const tokens = this.tokenizer.readLiquidTagTokens(this.liquid.options);
3842
- this.templates = this.liquid.parser.parseTokens(tokens);
4056
+ this.templates = parser.parseTokens(tokens);
3843
4057
  }
3844
4058
  *render(ctx, emitter) {
3845
4059
  yield this.liquid.renderer.renderTemplates(this.templates, ctx, emitter);
@@ -3886,12 +4100,14 @@ class Liquid {
3886
4100
  this.filters = {};
3887
4101
  this.tags = {};
3888
4102
  this.options = normalize(opts);
4103
+ // eslint-disable-next-line deprecation/deprecation
3889
4104
  this.parser = new Parser(this);
3890
4105
  forOwn(tags, (conf, name) => this.registerTag(name, conf));
3891
4106
  forOwn(filters, (handler, name) => this.registerFilter(name, handler));
3892
4107
  }
3893
4108
  parse(html, filepath) {
3894
- return this.parser.parse(html, filepath);
4109
+ const parser = new Parser(this);
4110
+ return parser.parse(html, filepath);
3895
4111
  }
3896
4112
  _render(tpl, scope, renderOptions) {
3897
4113
  const ctx = scope instanceof Context ? scope : new Context(scope, this.options, renderOptions);
@@ -3922,21 +4138,21 @@ class Liquid {
3922
4138
  return toValueSync(this._parseAndRender(html, scope, Object.assign(Object.assign({}, renderOptions), { sync: true })));
3923
4139
  }
3924
4140
  _parsePartialFile(file, sync, currentFile) {
3925
- return this.parser.parseFile(file, sync, LookupType.Partials, currentFile);
4141
+ return new Parser(this).parseFile(file, sync, LookupType.Partials, currentFile);
3926
4142
  }
3927
4143
  _parseLayoutFile(file, sync, currentFile) {
3928
- return this.parser.parseFile(file, sync, LookupType.Layouts, currentFile);
4144
+ return new Parser(this).parseFile(file, sync, LookupType.Layouts, currentFile);
3929
4145
  }
3930
4146
  _parseFile(file, sync, lookupType, currentFile) {
3931
- return this.parser.parseFile(file, sync, lookupType, currentFile);
4147
+ return new Parser(this).parseFile(file, sync, lookupType, currentFile);
3932
4148
  }
3933
4149
  parseFile(file, lookupType) {
3934
4150
  return __awaiter(this, void 0, void 0, function* () {
3935
- return toPromise(this.parser.parseFile(file, false, lookupType));
4151
+ return toPromise(new Parser(this).parseFile(file, false, lookupType));
3936
4152
  });
3937
4153
  }
3938
4154
  parseFileSync(file, lookupType) {
3939
- return toValueSync(this.parser.parseFile(file, true, lookupType));
4155
+ return toValueSync(new Parser(this).parseFile(file, true, lookupType));
3940
4156
  }
3941
4157
  *_renderFile(file, ctx, renderFileOptions) {
3942
4158
  const templates = (yield this._parseFile(file, renderFileOptions.sync, renderFileOptions.lookupType));
@@ -3995,6 +4211,6 @@ class Liquid {
3995
4211
  }
3996
4212
 
3997
4213
  /* istanbul ignore file */
3998
- const version = '10.13.0';
4214
+ const version = '[VI]{version}[/VI]';
3999
4215
 
4000
- 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 };
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 };