@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.
- package/.jsii +113 -3
- package/API.md +74 -43
- package/lib/skep-organization-project.js +1 -1
- package/node_modules/liquidjs/README.md +17 -10
- package/node_modules/liquidjs/dist/context/context.d.ts +7 -1
- package/node_modules/liquidjs/dist/drop/drop.d.ts +1 -1
- package/node_modules/liquidjs/dist/filters/array.d.ts +14 -14
- package/node_modules/liquidjs/dist/filters/html.d.ts +6 -5
- package/node_modules/liquidjs/dist/filters/math.d.ts +9 -9
- package/node_modules/liquidjs/dist/filters/string.d.ts +22 -21
- package/node_modules/liquidjs/dist/fs/map-fs.d.ts +13 -0
- package/node_modules/liquidjs/dist/fs/node-require.d.ts +1 -2
- package/node_modules/liquidjs/dist/index.d.ts +1 -1
- package/node_modules/liquidjs/dist/liquid-options.d.ts +28 -2
- package/node_modules/liquidjs/dist/liquid.browser.min.js +1 -1
- package/node_modules/liquidjs/dist/liquid.browser.min.js.map +1 -1
- package/node_modules/liquidjs/dist/{liquid.browser.esm.js → liquid.browser.mjs} +443 -227
- package/node_modules/liquidjs/dist/liquid.browser.umd.js +604 -368
- package/node_modules/liquidjs/dist/liquid.browser.umd.js.map +1 -1
- package/node_modules/liquidjs/dist/liquid.d.ts +3 -0
- package/node_modules/liquidjs/dist/{liquid.node.cjs.js → liquid.node.js} +432 -227
- package/node_modules/liquidjs/dist/{liquid.node.esm.js → liquid.node.mjs} +448 -228
- package/node_modules/liquidjs/dist/parser/parser.d.ts +1 -0
- package/node_modules/liquidjs/dist/parser/parser.spec.d.ts +1 -0
- package/node_modules/liquidjs/dist/parser/tokenizer.d.ts +4 -3
- package/node_modules/liquidjs/dist/tags/block.d.ts +2 -1
- package/node_modules/liquidjs/dist/tags/capture.d.ts +2 -1
- package/node_modules/liquidjs/dist/tags/case.d.ts +2 -1
- package/node_modules/liquidjs/dist/tags/for.d.ts +2 -1
- package/node_modules/liquidjs/dist/tags/if.d.ts +3 -2
- package/node_modules/liquidjs/dist/tags/include.d.ts +2 -1
- package/node_modules/liquidjs/dist/tags/layout.d.ts +2 -1
- package/node_modules/liquidjs/dist/tags/liquid.d.ts +2 -1
- package/node_modules/liquidjs/dist/tags/render.d.ts +3 -2
- package/node_modules/liquidjs/dist/tags/tablerow.d.ts +2 -1
- package/node_modules/liquidjs/dist/tags/unless.d.ts +2 -1
- package/node_modules/liquidjs/dist/template/filter-impl-options.d.ts +2 -0
- package/node_modules/liquidjs/dist/template/filter.d.ts +3 -1
- package/node_modules/liquidjs/dist/template/hash.d.ts +1 -1
- package/node_modules/liquidjs/dist/template/tag.d.ts +2 -2
- package/node_modules/liquidjs/dist/tokens/identifier-token.d.ts +0 -1
- package/node_modules/liquidjs/dist/util/assert.d.ts +1 -0
- package/node_modules/liquidjs/dist/util/error.d.ts +7 -2
- package/node_modules/liquidjs/dist/util/error.spec.d.ts +1 -0
- package/node_modules/liquidjs/dist/util/index.d.ts +2 -1
- package/node_modules/liquidjs/dist/util/intl.d.ts +6 -0
- package/node_modules/liquidjs/dist/util/limiter.d.ts +8 -0
- package/node_modules/liquidjs/dist/util/liquid-date.d.ts +39 -7
- package/node_modules/liquidjs/dist/util/liquid-date.spec.d.ts +1 -0
- package/node_modules/liquidjs/dist/util/performance.d.ts +5 -0
- package/node_modules/liquidjs/dist/util/performance.spec.d.ts +1 -0
- package/node_modules/liquidjs/dist/util/type-guards.spec.d.ts +1 -0
- package/node_modules/liquidjs/dist/util/underscore.d.ts +2 -1
- package/node_modules/liquidjs/package.json +10 -7
- package/package.json +16 -12
- package/node_modules/liquidjs/dist/util/timezone-date.d.ts +0 -44
- /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.
|
|
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)
|
|
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
|
|
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 &&
|
|
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
|
-
|
|
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) =>
|
|
666
|
-
A: (d) =>
|
|
667
|
-
b: (d) =>
|
|
668
|
-
B: (d) =>
|
|
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 =
|
|
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
|
|
757
|
-
constructor(init, timezone) {
|
|
758
|
-
this.
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
this.
|
|
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
|
-
|
|
810
|
-
|
|
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
|
|
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
|
|
875
|
+
return new LiquidDate(+new Date(dateString), locale, offset);
|
|
836
876
|
}
|
|
837
|
-
return new
|
|
877
|
+
return new LiquidDate(dateString, locale);
|
|
838
878
|
}
|
|
839
|
-
static getTimezoneOffset(timezoneName, 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 =
|
|
1192
|
-
|
|
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
|
-
|
|
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
|
''': "'"
|
|
1532
1600
|
};
|
|
1533
1601
|
function escape(str) {
|
|
1534
|
-
|
|
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
|
-
|
|
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(
|
|
1615
|
+
return escape.call(this, unescape.call(this, str));
|
|
1544
1616
|
}
|
|
1545
1617
|
function newline_to_br(v) {
|
|
1546
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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(
|
|
2214
|
-
this.
|
|
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(
|
|
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
|
-
|
|
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 = (
|
|
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
|
-
|
|
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.
|
|
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 && !
|
|
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 (
|
|
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)
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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,
|
|
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
|
-
|
|
2808
|
-
|
|
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,
|
|
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
|
-
|
|
2830
|
-
|
|
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
|
-
|
|
2840
|
-
|
|
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
|
-
|
|
2849
|
-
|
|
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 =
|
|
2857
|
-
|
|
2858
|
-
return (arr
|
|
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
|
|
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
|
|
3149
|
+
date = new LiquidDate(+v * 1000, locale, defaultTimezoneOffset);
|
|
2949
3150
|
}
|
|
2950
|
-
else if (opts.preserveTimezones) {
|
|
2951
|
-
date =
|
|
3151
|
+
else if (opts.preserveTimezones && timezoneOffset === undefined) {
|
|
3152
|
+
date = LiquidDate.createDateFixedToTimezone(v, locale);
|
|
2952
3153
|
}
|
|
2953
3154
|
else {
|
|
2954
|
-
date = new
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3200
|
+
return str.replace(new RegExp(`^[${chars}]+`, 'g'), '');
|
|
3003
3201
|
}
|
|
3004
|
-
return
|
|
3202
|
+
return str.replace(/^\s+/, '');
|
|
3005
3203
|
}
|
|
3006
3204
|
function downcase(v) {
|
|
3007
|
-
|
|
3205
|
+
const str = stringify(v);
|
|
3206
|
+
this.context.memoryLimit.use(str.length);
|
|
3207
|
+
return str.toLowerCase();
|
|
3008
3208
|
}
|
|
3009
|
-
function upcase(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3238
|
+
return str.replace(new RegExp(`[${chars}]+$`, 'g'), '');
|
|
3030
3239
|
}
|
|
3031
|
-
return
|
|
3240
|
+
return str.replace(/\s+$/, '');
|
|
3032
3241
|
}
|
|
3033
3242
|
function split(v, arg) {
|
|
3034
|
-
const
|
|
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
|
|
3257
|
+
return str
|
|
3045
3258
|
.replace(new RegExp(`^[${chars}]+`, 'g'), '')
|
|
3046
3259
|
.replace(new RegExp(`[${chars}]+$`, 'g'), '');
|
|
3047
3260
|
}
|
|
3048
|
-
return
|
|
3261
|
+
return str.trim();
|
|
3049
3262
|
}
|
|
3050
3263
|
function strip_newlines(v) {
|
|
3051
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3074
|
-
|
|
3294
|
+
const str = stringify(v);
|
|
3295
|
+
this.context.memoryLimit.use(str.length);
|
|
3296
|
+
if (str.length <= l)
|
|
3075
3297
|
return v;
|
|
3076
|
-
return
|
|
3298
|
+
return str.substring(0, l - o.length) + o;
|
|
3077
3299
|
}
|
|
3078
3300
|
function truncatewords(v, words = 15, o = '...') {
|
|
3079
|
-
const
|
|
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
|
-
|
|
3089
|
-
|
|
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
|
-
|
|
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 =
|
|
3408
|
+
const stream = parser.parseStream(remainTokens)
|
|
3181
3409
|
.on('start', () => (p = this.templates))
|
|
3182
|
-
.on('tag:else',
|
|
3183
|
-
.on('tag:endfor', ()
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(),
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3564
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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.
|
|
4154
|
+
return new Parser(this).parseFile(file, sync, LookupType.Partials, currentFile);
|
|
3935
4155
|
}
|
|
3936
4156
|
_parseLayoutFile(file, sync, currentFile) {
|
|
3937
|
-
return this.
|
|
4157
|
+
return new Parser(this).parseFile(file, sync, LookupType.Layouts, currentFile);
|
|
3938
4158
|
}
|
|
3939
4159
|
_parseFile(file, sync, lookupType, currentFile) {
|
|
3940
|
-
return this.
|
|
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.
|
|
4164
|
+
return toPromise(new Parser(this).parseFile(file, false, lookupType));
|
|
3945
4165
|
});
|
|
3946
4166
|
}
|
|
3947
4167
|
parseFileSync(file, lookupType) {
|
|
3948
|
-
return toValueSync(this.
|
|
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 = '
|
|
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,
|
|
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 };
|