directus-extension-texttoanything 1.1.3 → 1.3.0
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/dist/api.js +1877 -587
- package/dist/app.js +5195 -69
- package/package.json +6 -1
package/dist/api.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var stream = require('stream');
|
|
4
4
|
var require$$1$1 = require('path');
|
|
5
5
|
var require$$6 = require('fs');
|
|
6
|
+
var module$1 = require('module');
|
|
6
7
|
var require$$1 = require('util');
|
|
7
8
|
var require$$3 = require('http');
|
|
8
9
|
var require$$4 = require('https');
|
|
@@ -107,7 +108,7 @@ const {isArray: isArray$1} = Array;
|
|
|
107
108
|
*
|
|
108
109
|
* @returns {boolean} True if the value is undefined, otherwise false
|
|
109
110
|
*/
|
|
110
|
-
const isUndefined = typeOfTest('undefined');
|
|
111
|
+
const isUndefined$1 = typeOfTest('undefined');
|
|
111
112
|
|
|
112
113
|
/**
|
|
113
114
|
* Determine if a value is a Buffer
|
|
@@ -117,7 +118,7 @@ const isUndefined = typeOfTest('undefined');
|
|
|
117
118
|
* @returns {boolean} True if value is a Buffer, otherwise false
|
|
118
119
|
*/
|
|
119
120
|
function isBuffer$1(val) {
|
|
120
|
-
return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)
|
|
121
|
+
return val !== null && !isUndefined$1(val) && val.constructor !== null && !isUndefined$1(val.constructor)
|
|
121
122
|
&& isFunction$2(val.constructor.isBuffer) && val.constructor.isBuffer(val);
|
|
122
123
|
}
|
|
123
124
|
|
|
@@ -650,7 +651,7 @@ var utils = {
|
|
|
650
651
|
isBoolean,
|
|
651
652
|
isObject: isObject$1,
|
|
652
653
|
isPlainObject,
|
|
653
|
-
isUndefined,
|
|
654
|
+
isUndefined: isUndefined$1,
|
|
654
655
|
isDate,
|
|
655
656
|
isFile,
|
|
656
657
|
isBlob,
|
|
@@ -17544,8 +17545,8 @@ axios.formToJSON = thing => {
|
|
|
17544
17545
|
};
|
|
17545
17546
|
|
|
17546
17547
|
/*
|
|
17547
|
-
* liquidjs@10.
|
|
17548
|
-
* (c) 2016-
|
|
17548
|
+
* liquidjs@10.20.1, https://github.com/harttle/liquidjs
|
|
17549
|
+
* (c) 2016-2025 harttle
|
|
17549
17550
|
* Released under the MIT License.
|
|
17550
17551
|
*/
|
|
17551
17552
|
|
|
@@ -17621,9 +17622,33 @@ function stringify(value) {
|
|
|
17621
17622
|
return value.map(x => stringify(x)).join('');
|
|
17622
17623
|
return String(value);
|
|
17623
17624
|
}
|
|
17625
|
+
function toEnumerable(val) {
|
|
17626
|
+
val = toValue(val);
|
|
17627
|
+
if (isArray(val))
|
|
17628
|
+
return val;
|
|
17629
|
+
if (isString(val) && val.length > 0)
|
|
17630
|
+
return [val];
|
|
17631
|
+
if (isIterable(val))
|
|
17632
|
+
return Array.from(val);
|
|
17633
|
+
if (isObject(val))
|
|
17634
|
+
return Object.keys(val).map((key) => [key, val[key]]);
|
|
17635
|
+
return [];
|
|
17636
|
+
}
|
|
17637
|
+
function toArray(val) {
|
|
17638
|
+
val = toValue(val);
|
|
17639
|
+
if (isNil(val))
|
|
17640
|
+
return [];
|
|
17641
|
+
if (isArray(val))
|
|
17642
|
+
return val;
|
|
17643
|
+
return [val];
|
|
17644
|
+
}
|
|
17624
17645
|
function toValue(value) {
|
|
17625
17646
|
return (value instanceof Drop && isFunction(value.valueOf)) ? value.valueOf() : value;
|
|
17626
17647
|
}
|
|
17648
|
+
function toNumber(value) {
|
|
17649
|
+
value = Number(value);
|
|
17650
|
+
return isNaN(value) ? 0 : value;
|
|
17651
|
+
}
|
|
17627
17652
|
function isNumber(value) {
|
|
17628
17653
|
return typeof value === 'number';
|
|
17629
17654
|
}
|
|
@@ -17635,10 +17660,16 @@ function toLiquid(value) {
|
|
|
17635
17660
|
function isNil(value) {
|
|
17636
17661
|
return value == null;
|
|
17637
17662
|
}
|
|
17663
|
+
function isUndefined(value) {
|
|
17664
|
+
return value === undefined;
|
|
17665
|
+
}
|
|
17638
17666
|
function isArray(value) {
|
|
17639
17667
|
// be compatible with IE 8
|
|
17640
17668
|
return toString$1.call(value) === '[object Array]';
|
|
17641
17669
|
}
|
|
17670
|
+
function isArrayLike(value) {
|
|
17671
|
+
return value && isNumber(value.length);
|
|
17672
|
+
}
|
|
17642
17673
|
function isIterable(value) {
|
|
17643
17674
|
return isObject(value) && Symbol.iterator in value;
|
|
17644
17675
|
}
|
|
@@ -17720,30 +17751,55 @@ function caseInsensitiveCompare(a, b) {
|
|
|
17720
17751
|
return 0;
|
|
17721
17752
|
}
|
|
17722
17753
|
function argumentsToValue(fn) {
|
|
17723
|
-
return (...args)
|
|
17754
|
+
return function (...args) { return fn.call(this, ...args.map(toValue)); };
|
|
17724
17755
|
}
|
|
17725
17756
|
function escapeRegExp(text) {
|
|
17726
17757
|
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
17758
|
+
}
|
|
17759
|
+
/** Return an array containing unique elements from _array_. Works with nested arrays and objects. */
|
|
17760
|
+
function* strictUniq(array) {
|
|
17761
|
+
const seen = new Set();
|
|
17762
|
+
for (const element of array) {
|
|
17763
|
+
const key = JSON.stringify(element);
|
|
17764
|
+
if (!seen.has(key)) {
|
|
17765
|
+
seen.add(key);
|
|
17766
|
+
yield element;
|
|
17767
|
+
}
|
|
17768
|
+
}
|
|
17727
17769
|
}
|
|
17728
17770
|
|
|
17771
|
+
/**
|
|
17772
|
+
* targeting ES5, extends Error won't create a proper prototype chain, need a trait to keep track of classes
|
|
17773
|
+
*/
|
|
17774
|
+
const TRAIT = '__liquidClass__';
|
|
17729
17775
|
class LiquidError extends Error {
|
|
17730
17776
|
constructor(err, token) {
|
|
17731
|
-
|
|
17732
|
-
|
|
17733
|
-
|
|
17777
|
+
/**
|
|
17778
|
+
* note: for ES5 targeting, `this` will be replaced by return value of Error(),
|
|
17779
|
+
* thus everything on `this` will be lost, avoid calling `LiquidError` methods here
|
|
17780
|
+
*/
|
|
17781
|
+
super(typeof err === 'string' ? err : err.message);
|
|
17734
17782
|
this.context = '';
|
|
17783
|
+
if (typeof err !== 'string')
|
|
17784
|
+
Object.defineProperty(this, 'originalError', { value: err, enumerable: false });
|
|
17785
|
+
Object.defineProperty(this, 'token', { value: token, enumerable: false });
|
|
17786
|
+
Object.defineProperty(this, TRAIT, { value: 'LiquidError', enumerable: false });
|
|
17735
17787
|
}
|
|
17736
17788
|
update() {
|
|
17737
|
-
|
|
17738
|
-
this.
|
|
17739
|
-
this.message = mkMessage(err.message, this.token);
|
|
17789
|
+
Object.defineProperty(this, 'context', { value: mkContext(this.token), enumerable: false });
|
|
17790
|
+
this.message = mkMessage(this.message, this.token);
|
|
17740
17791
|
this.stack = this.message + '\n' + this.context +
|
|
17741
|
-
'\n' + this.stack
|
|
17792
|
+
'\n' + this.stack;
|
|
17793
|
+
if (this.originalError)
|
|
17794
|
+
this.stack += '\nFrom ' + this.originalError.stack;
|
|
17795
|
+
}
|
|
17796
|
+
static is(obj) {
|
|
17797
|
+
return (obj === null || obj === void 0 ? void 0 : obj[TRAIT]) === 'LiquidError';
|
|
17742
17798
|
}
|
|
17743
17799
|
}
|
|
17744
17800
|
class TokenizationError extends LiquidError {
|
|
17745
17801
|
constructor(message, token) {
|
|
17746
|
-
super(
|
|
17802
|
+
super(message, token);
|
|
17747
17803
|
this.name = 'TokenizationError';
|
|
17748
17804
|
super.update();
|
|
17749
17805
|
}
|
|
@@ -17767,6 +17823,19 @@ class RenderError extends LiquidError {
|
|
|
17767
17823
|
return obj.name === 'RenderError';
|
|
17768
17824
|
}
|
|
17769
17825
|
}
|
|
17826
|
+
class LiquidErrors extends LiquidError {
|
|
17827
|
+
constructor(errors) {
|
|
17828
|
+
super(errors[0], errors[0].token);
|
|
17829
|
+
this.errors = errors;
|
|
17830
|
+
this.name = 'LiquidErrors';
|
|
17831
|
+
const s = errors.length > 1 ? 's' : '';
|
|
17832
|
+
this.message = `${errors.length} error${s} found`;
|
|
17833
|
+
super.update();
|
|
17834
|
+
}
|
|
17835
|
+
static is(obj) {
|
|
17836
|
+
return obj.name === 'LiquidErrors';
|
|
17837
|
+
}
|
|
17838
|
+
}
|
|
17770
17839
|
class UndefinedVariableError extends LiquidError {
|
|
17771
17840
|
constructor(err, token) {
|
|
17772
17841
|
super(err, token);
|
|
@@ -17792,16 +17861,21 @@ class AssertionError extends Error {
|
|
|
17792
17861
|
}
|
|
17793
17862
|
}
|
|
17794
17863
|
function mkContext(token) {
|
|
17795
|
-
const [line] = token.getPosition();
|
|
17864
|
+
const [line, col] = token.getPosition();
|
|
17796
17865
|
const lines = token.input.split('\n');
|
|
17797
17866
|
const begin = Math.max(line - 2, 1);
|
|
17798
17867
|
const end = Math.min(line + 3, lines.length);
|
|
17799
17868
|
const context = range(begin, end + 1)
|
|
17800
17869
|
.map(lineNumber => {
|
|
17801
|
-
const
|
|
17870
|
+
const rowIndicator = (lineNumber === line) ? '>> ' : ' ';
|
|
17802
17871
|
const num = padStart(String(lineNumber), String(end).length);
|
|
17803
|
-
|
|
17804
|
-
|
|
17872
|
+
let text = `${rowIndicator}${num}| `;
|
|
17873
|
+
const colIndicator = lineNumber === line
|
|
17874
|
+
? '\n' + padStart('^', col + text.length)
|
|
17875
|
+
: '';
|
|
17876
|
+
text += lines[lineNumber - 1];
|
|
17877
|
+
text += colIndicator;
|
|
17878
|
+
return text;
|
|
17805
17879
|
})
|
|
17806
17880
|
.join('\n');
|
|
17807
17881
|
return context;
|
|
@@ -17819,13 +17893,19 @@ function mkMessage(msg, token) {
|
|
|
17819
17893
|
// This file is generated by bin/character-gen.js
|
|
17820
17894
|
// bitmask character types to boost performance
|
|
17821
17895
|
const TYPES = [0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 4, 4, 4, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 2, 8, 0, 0, 0, 0, 8, 0, 0, 0, 64, 0, 65, 0, 0, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 0, 0, 2, 2, 2, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0];
|
|
17822
|
-
const
|
|
17896
|
+
const WORD = 1;
|
|
17823
17897
|
const BLANK = 4;
|
|
17824
17898
|
const QUOTE = 8;
|
|
17825
17899
|
const INLINE_BLANK = 16;
|
|
17826
17900
|
const NUMBER = 32;
|
|
17827
17901
|
const SIGN = 64;
|
|
17828
|
-
|
|
17902
|
+
const PUNCTUATION = 128;
|
|
17903
|
+
function isWord(char) {
|
|
17904
|
+
const code = char.charCodeAt(0);
|
|
17905
|
+
return code >= 128 ? !TYPES[code] : !!(TYPES[code] & WORD);
|
|
17906
|
+
}
|
|
17907
|
+
TYPES[160] = TYPES[5760] = TYPES[6158] = TYPES[8192] = TYPES[8193] = TYPES[8194] = TYPES[8195] = TYPES[8196] = TYPES[8197] = TYPES[8198] = TYPES[8199] = TYPES[8200] = TYPES[8201] = TYPES[8202] = TYPES[8232] = TYPES[8233] = TYPES[8239] = TYPES[8287] = TYPES[12288] = BLANK;
|
|
17908
|
+
TYPES[8220] = TYPES[8221] = PUNCTUATION;
|
|
17829
17909
|
|
|
17830
17910
|
function assert(predicate, message) {
|
|
17831
17911
|
if (!predicate) {
|
|
@@ -17834,6 +17914,9 @@ function assert(predicate, message) {
|
|
|
17834
17914
|
: (message || `expect ${predicate} to be true`);
|
|
17835
17915
|
throw new AssertionError(msg);
|
|
17836
17916
|
}
|
|
17917
|
+
}
|
|
17918
|
+
function assertEmpty(predicate, message = `unexpected ${JSON.stringify(predicate)}`) {
|
|
17919
|
+
assert(!predicate, message);
|
|
17837
17920
|
}
|
|
17838
17921
|
|
|
17839
17922
|
class NullDrop extends Drop {
|
|
@@ -17883,6 +17966,9 @@ class EmptyDrop extends Drop {
|
|
|
17883
17966
|
valueOf() {
|
|
17884
17967
|
return '';
|
|
17885
17968
|
}
|
|
17969
|
+
static is(value) {
|
|
17970
|
+
return value instanceof EmptyDrop;
|
|
17971
|
+
}
|
|
17886
17972
|
}
|
|
17887
17973
|
|
|
17888
17974
|
class BlankDrop extends EmptyDrop {
|
|
@@ -17895,6 +17981,9 @@ class BlankDrop extends EmptyDrop {
|
|
|
17895
17981
|
return /^\s*$/.test(value);
|
|
17896
17982
|
return super.equals(value);
|
|
17897
17983
|
}
|
|
17984
|
+
static is(value) {
|
|
17985
|
+
return value instanceof BlankDrop;
|
|
17986
|
+
}
|
|
17898
17987
|
}
|
|
17899
17988
|
|
|
17900
17989
|
class ForloopDrop extends Drop {
|
|
@@ -17947,7 +18036,12 @@ class BlockDrop extends Drop {
|
|
|
17947
18036
|
}
|
|
17948
18037
|
|
|
17949
18038
|
function isComparable(arg) {
|
|
17950
|
-
return arg &&
|
|
18039
|
+
return (arg &&
|
|
18040
|
+
isFunction(arg.equals) &&
|
|
18041
|
+
isFunction(arg.gt) &&
|
|
18042
|
+
isFunction(arg.geq) &&
|
|
18043
|
+
isFunction(arg.lt) &&
|
|
18044
|
+
isFunction(arg.leq));
|
|
17951
18045
|
}
|
|
17952
18046
|
|
|
17953
18047
|
const nil = new NullDrop();
|
|
@@ -17960,19 +18054,19 @@ const literalValues = {
|
|
|
17960
18054
|
'blank': new BlankDrop()
|
|
17961
18055
|
};
|
|
17962
18056
|
|
|
17963
|
-
function createTrie(
|
|
18057
|
+
function createTrie(input) {
|
|
17964
18058
|
const trie = {};
|
|
17965
|
-
for (const [name,
|
|
18059
|
+
for (const [name, data] of Object.entries(input)) {
|
|
17966
18060
|
let node = trie;
|
|
17967
18061
|
for (let i = 0; i < name.length; i++) {
|
|
17968
18062
|
const c = name[i];
|
|
17969
18063
|
node[c] = node[c] || {};
|
|
17970
|
-
if (i === name.length - 1 && (
|
|
18064
|
+
if (i === name.length - 1 && isWord(name[i])) {
|
|
17971
18065
|
node[c].needBoundary = true;
|
|
17972
18066
|
}
|
|
17973
18067
|
node = node[c];
|
|
17974
18068
|
}
|
|
17975
|
-
node.
|
|
18069
|
+
node.data = data;
|
|
17976
18070
|
node.end = true;
|
|
17977
18071
|
}
|
|
17978
18072
|
return trie;
|
|
@@ -18066,45 +18160,7 @@ function toValueSync(val) {
|
|
|
18066
18160
|
return value;
|
|
18067
18161
|
}
|
|
18068
18162
|
|
|
18069
|
-
function toEnumerable(val) {
|
|
18070
|
-
val = toValue(val);
|
|
18071
|
-
if (isArray(val))
|
|
18072
|
-
return val;
|
|
18073
|
-
if (isString(val) && val.length > 0)
|
|
18074
|
-
return [val];
|
|
18075
|
-
if (isIterable(val))
|
|
18076
|
-
return Array.from(val);
|
|
18077
|
-
if (isObject(val))
|
|
18078
|
-
return Object.keys(val).map((key) => [key, val[key]]);
|
|
18079
|
-
return [];
|
|
18080
|
-
}
|
|
18081
|
-
function toArray(val) {
|
|
18082
|
-
if (isNil(val))
|
|
18083
|
-
return [];
|
|
18084
|
-
if (isArray(val))
|
|
18085
|
-
return val;
|
|
18086
|
-
return [val];
|
|
18087
|
-
}
|
|
18088
|
-
|
|
18089
18163
|
const rFormat = /%([-_0^#:]+)?(\d+)?([EO])?(.)/;
|
|
18090
|
-
const monthNames = [
|
|
18091
|
-
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
|
|
18092
|
-
'September', 'October', 'November', 'December'
|
|
18093
|
-
];
|
|
18094
|
-
const dayNames = [
|
|
18095
|
-
'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
|
|
18096
|
-
];
|
|
18097
|
-
const monthNamesShort = monthNames.map(abbr);
|
|
18098
|
-
const dayNamesShort = dayNames.map(abbr);
|
|
18099
|
-
const suffixes = {
|
|
18100
|
-
1: 'st',
|
|
18101
|
-
2: 'nd',
|
|
18102
|
-
3: 'rd',
|
|
18103
|
-
'default': 'th'
|
|
18104
|
-
};
|
|
18105
|
-
function abbr(str) {
|
|
18106
|
-
return str.slice(0, 3);
|
|
18107
|
-
}
|
|
18108
18164
|
// prototype extensions
|
|
18109
18165
|
function daysInMonth(d) {
|
|
18110
18166
|
const feb = isLeapYear(d) ? 29 : 28;
|
|
@@ -18129,10 +18185,16 @@ function isLeapYear(d) {
|
|
|
18129
18185
|
const year = d.getFullYear();
|
|
18130
18186
|
return !!((year & 3) === 0 && (year % 100 || (year % 400 === 0 && year)));
|
|
18131
18187
|
}
|
|
18132
|
-
function
|
|
18133
|
-
const
|
|
18134
|
-
|
|
18135
|
-
|
|
18188
|
+
function ordinal(d) {
|
|
18189
|
+
const date = d.getDate();
|
|
18190
|
+
if ([11, 12, 13].includes(date))
|
|
18191
|
+
return 'th';
|
|
18192
|
+
switch (date % 10) {
|
|
18193
|
+
case 1: return 'st';
|
|
18194
|
+
case 2: return 'nd';
|
|
18195
|
+
case 3: return 'rd';
|
|
18196
|
+
default: return 'th';
|
|
18197
|
+
}
|
|
18136
18198
|
}
|
|
18137
18199
|
function century(d) {
|
|
18138
18200
|
return parseInt(d.getFullYear().toString().substring(0, 2), 10);
|
|
@@ -18153,24 +18215,21 @@ const padWidths = {
|
|
|
18153
18215
|
U: 2,
|
|
18154
18216
|
W: 2
|
|
18155
18217
|
};
|
|
18156
|
-
|
|
18157
|
-
|
|
18158
|
-
|
|
18159
|
-
|
|
18160
|
-
|
|
18161
|
-
|
|
18162
|
-
|
|
18163
|
-
|
|
18164
|
-
|
|
18165
|
-
|
|
18166
|
-
p: ' ',
|
|
18167
|
-
P: ' '
|
|
18168
|
-
};
|
|
18218
|
+
const padSpaceChars = new Set('aAbBceklpP');
|
|
18219
|
+
function getTimezoneOffset(d, opts) {
|
|
18220
|
+
const nOffset = Math.abs(d.getTimezoneOffset());
|
|
18221
|
+
const h = Math.floor(nOffset / 60);
|
|
18222
|
+
const m = nOffset % 60;
|
|
18223
|
+
return (d.getTimezoneOffset() > 0 ? '-' : '+') +
|
|
18224
|
+
padStart(h, 2, '0') +
|
|
18225
|
+
(opts.flags[':'] ? ':' : '') +
|
|
18226
|
+
padStart(m, 2, '0');
|
|
18227
|
+
}
|
|
18169
18228
|
const formatCodes = {
|
|
18170
|
-
a: (d) =>
|
|
18171
|
-
A: (d) =>
|
|
18172
|
-
b: (d) =>
|
|
18173
|
-
B: (d) =>
|
|
18229
|
+
a: (d) => d.getShortWeekdayName(),
|
|
18230
|
+
A: (d) => d.getLongWeekdayName(),
|
|
18231
|
+
b: (d) => d.getShortMonthName(),
|
|
18232
|
+
B: (d) => d.getLongMonthName(),
|
|
18174
18233
|
c: (d) => d.toLocaleString(),
|
|
18175
18234
|
C: (d) => century(d),
|
|
18176
18235
|
d: (d) => d.getDate(),
|
|
@@ -18190,7 +18249,7 @@ const formatCodes = {
|
|
|
18190
18249
|
},
|
|
18191
18250
|
p: (d) => (d.getHours() < 12 ? 'AM' : 'PM'),
|
|
18192
18251
|
P: (d) => (d.getHours() < 12 ? 'am' : 'pm'),
|
|
18193
|
-
q: (d) =>
|
|
18252
|
+
q: (d) => ordinal(d),
|
|
18194
18253
|
s: (d) => Math.round(d.getTime() / 1000),
|
|
18195
18254
|
S: (d) => d.getSeconds(),
|
|
18196
18255
|
u: (d) => d.getDay() || 7,
|
|
@@ -18201,15 +18260,8 @@ const formatCodes = {
|
|
|
18201
18260
|
X: (d) => d.toLocaleTimeString(),
|
|
18202
18261
|
y: (d) => d.getFullYear().toString().slice(2, 4),
|
|
18203
18262
|
Y: (d) => d.getFullYear(),
|
|
18204
|
-
z:
|
|
18205
|
-
|
|
18206
|
-
const h = Math.floor(nOffset / 60);
|
|
18207
|
-
const m = nOffset % 60;
|
|
18208
|
-
return (d.getTimezoneOffset() > 0 ? '-' : '+') +
|
|
18209
|
-
padStart(h, 2, '0') +
|
|
18210
|
-
(opts.flags[':'] ? ':' : '') +
|
|
18211
|
-
padStart(m, 2, '0');
|
|
18212
|
-
},
|
|
18263
|
+
z: getTimezoneOffset,
|
|
18264
|
+
Z: (d, opts) => d.getTimeZoneName() || getTimezoneOffset(d, opts),
|
|
18213
18265
|
't': () => '\t',
|
|
18214
18266
|
'n': () => '\n',
|
|
18215
18267
|
'%': () => '%'
|
|
@@ -18235,7 +18287,7 @@ function format(d, match) {
|
|
|
18235
18287
|
for (const flag of flagStr)
|
|
18236
18288
|
flags[flag] = true;
|
|
18237
18289
|
let ret = String(convert(d, { flags, width, modifier }));
|
|
18238
|
-
let padChar =
|
|
18290
|
+
let padChar = padSpaceChars.has(conversion) ? ' ' : '0';
|
|
18239
18291
|
let padWidth = width || padWidths[conversion] || 0;
|
|
18240
18292
|
if (flags['^'])
|
|
18241
18293
|
ret = ret.toUpperCase();
|
|
@@ -18250,9 +18302,26 @@ function format(d, match) {
|
|
|
18250
18302
|
return padStart(ret, padWidth, padChar);
|
|
18251
18303
|
}
|
|
18252
18304
|
|
|
18305
|
+
function getDateTimeFormat() {
|
|
18306
|
+
return (typeof Intl !== 'undefined' ? Intl.DateTimeFormat : undefined);
|
|
18307
|
+
}
|
|
18308
|
+
|
|
18253
18309
|
// one minute in milliseconds
|
|
18254
18310
|
const OneMinute = 60000;
|
|
18255
|
-
|
|
18311
|
+
/**
|
|
18312
|
+
* Need support both ISO8601 and RFC2822 as in major browsers & NodeJS
|
|
18313
|
+
* RFC2822: https://datatracker.ietf.org/doc/html/rfc2822#section-3.3
|
|
18314
|
+
*/
|
|
18315
|
+
const TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):?(\d{2}))$/;
|
|
18316
|
+
const monthNames = [
|
|
18317
|
+
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
|
|
18318
|
+
'September', 'October', 'November', 'December'
|
|
18319
|
+
];
|
|
18320
|
+
const monthNamesShort = monthNames.map(name => name.slice(0, 3));
|
|
18321
|
+
const dayNames = [
|
|
18322
|
+
'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
|
|
18323
|
+
];
|
|
18324
|
+
const dayNamesShort = dayNames.map(name => name.slice(0, 3));
|
|
18256
18325
|
/**
|
|
18257
18326
|
* A date implementation with timezone info, just like Ruby date
|
|
18258
18327
|
*
|
|
@@ -18260,12 +18329,17 @@ const ISO8601_TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):(\d{2}))$/;
|
|
|
18260
18329
|
* - create a Date offset by it's timezone difference, avoiding overriding a bunch of methods
|
|
18261
18330
|
* - rewrite getTimezoneOffset() to trick strftime
|
|
18262
18331
|
*/
|
|
18263
|
-
class
|
|
18264
|
-
constructor(init,
|
|
18265
|
-
this.
|
|
18266
|
-
|
|
18267
|
-
|
|
18268
|
-
this.
|
|
18332
|
+
class LiquidDate {
|
|
18333
|
+
constructor(init, locale, timezone) {
|
|
18334
|
+
this.locale = locale;
|
|
18335
|
+
this.DateTimeFormat = getDateTimeFormat();
|
|
18336
|
+
this.date = new Date(init);
|
|
18337
|
+
this.timezoneFixed = timezone !== undefined;
|
|
18338
|
+
if (timezone === undefined) {
|
|
18339
|
+
timezone = this.date.getTimezoneOffset();
|
|
18340
|
+
}
|
|
18341
|
+
this.timezoneOffset = isString(timezone) ? LiquidDate.getTimezoneOffset(timezone, this.date) : timezone;
|
|
18342
|
+
this.timezoneName = isString(timezone) ? timezone : '';
|
|
18269
18343
|
const diff = (this.date.getTimezoneOffset() - this.timezoneOffset) * OneMinute;
|
|
18270
18344
|
const time = this.date.getTime() + diff;
|
|
18271
18345
|
this.displayDate = new Date(time);
|
|
@@ -18312,6 +18386,35 @@ class TimezoneDate {
|
|
|
18312
18386
|
getTimezoneOffset() {
|
|
18313
18387
|
return this.timezoneOffset;
|
|
18314
18388
|
}
|
|
18389
|
+
getTimeZoneName() {
|
|
18390
|
+
if (this.timezoneFixed)
|
|
18391
|
+
return this.timezoneName;
|
|
18392
|
+
if (!this.DateTimeFormat)
|
|
18393
|
+
return;
|
|
18394
|
+
return this.DateTimeFormat().resolvedOptions().timeZone;
|
|
18395
|
+
}
|
|
18396
|
+
getLongMonthName() {
|
|
18397
|
+
var _a;
|
|
18398
|
+
return (_a = this.format({ month: 'long' })) !== null && _a !== void 0 ? _a : monthNames[this.getMonth()];
|
|
18399
|
+
}
|
|
18400
|
+
getShortMonthName() {
|
|
18401
|
+
var _a;
|
|
18402
|
+
return (_a = this.format({ month: 'short' })) !== null && _a !== void 0 ? _a : monthNamesShort[this.getMonth()];
|
|
18403
|
+
}
|
|
18404
|
+
getLongWeekdayName() {
|
|
18405
|
+
var _a;
|
|
18406
|
+
return (_a = this.format({ weekday: 'long' })) !== null && _a !== void 0 ? _a : dayNames[this.displayDate.getDay()];
|
|
18407
|
+
}
|
|
18408
|
+
getShortWeekdayName() {
|
|
18409
|
+
var _a;
|
|
18410
|
+
return (_a = this.format({ weekday: 'short' })) !== null && _a !== void 0 ? _a : dayNamesShort[this.displayDate.getDay()];
|
|
18411
|
+
}
|
|
18412
|
+
valid() {
|
|
18413
|
+
return !isNaN(this.getTime());
|
|
18414
|
+
}
|
|
18415
|
+
format(options) {
|
|
18416
|
+
return this.DateTimeFormat && this.DateTimeFormat(this.locale, options).format(this.displayDate);
|
|
18417
|
+
}
|
|
18315
18418
|
/**
|
|
18316
18419
|
* Create a Date object fixed to it's declared Timezone. Both
|
|
18317
18420
|
* - 2021-08-06T02:29:00.000Z and
|
|
@@ -18325,57 +18428,88 @@ class TimezoneDate {
|
|
|
18325
18428
|
* we create a different Date to trick strftime, it's both simpler and more performant.
|
|
18326
18429
|
* Given that a template is expected to be parsed fewer times than rendered.
|
|
18327
18430
|
*/
|
|
18328
|
-
static createDateFixedToTimezone(dateString) {
|
|
18329
|
-
const m = dateString.match(
|
|
18431
|
+
static createDateFixedToTimezone(dateString, locale) {
|
|
18432
|
+
const m = dateString.match(TIMEZONE_PATTERN);
|
|
18330
18433
|
// representing a UTC timestamp
|
|
18331
18434
|
if (m && m[1] === 'Z') {
|
|
18332
|
-
return new
|
|
18435
|
+
return new LiquidDate(+new Date(dateString), locale, 0);
|
|
18333
18436
|
}
|
|
18334
18437
|
// has a timezone specified
|
|
18335
18438
|
if (m && m[2] && m[3] && m[4]) {
|
|
18336
18439
|
const [, , sign, hours, minutes] = m;
|
|
18337
18440
|
const offset = (sign === '+' ? -1 : 1) * (parseInt(hours, 10) * 60 + parseInt(minutes, 10));
|
|
18338
|
-
return new
|
|
18441
|
+
return new LiquidDate(+new Date(dateString), locale, offset);
|
|
18339
18442
|
}
|
|
18340
|
-
return new
|
|
18443
|
+
return new LiquidDate(dateString, locale);
|
|
18444
|
+
}
|
|
18445
|
+
static getTimezoneOffset(timezoneName, date) {
|
|
18446
|
+
const localDateString = date.toLocaleString('en-US', { timeZone: timezoneName });
|
|
18447
|
+
const utcDateString = date.toLocaleString('en-US', { timeZone: 'UTC' });
|
|
18448
|
+
const localDate = new Date(localDateString);
|
|
18449
|
+
const utcDate = new Date(utcDateString);
|
|
18450
|
+
return (+utcDate - +localDate) / (60 * 1000);
|
|
18451
|
+
}
|
|
18452
|
+
}
|
|
18453
|
+
|
|
18454
|
+
class Limiter {
|
|
18455
|
+
constructor(resource, limit) {
|
|
18456
|
+
this.base = 0;
|
|
18457
|
+
this.message = `${resource} limit exceeded`;
|
|
18458
|
+
this.limit = limit;
|
|
18459
|
+
}
|
|
18460
|
+
use(count) {
|
|
18461
|
+
count = toNumber(count);
|
|
18462
|
+
assert(this.base + count <= this.limit, this.message);
|
|
18463
|
+
this.base += count;
|
|
18464
|
+
}
|
|
18465
|
+
check(count) {
|
|
18466
|
+
count = toNumber(count);
|
|
18467
|
+
assert(count <= this.limit, this.message);
|
|
18341
18468
|
}
|
|
18342
18469
|
}
|
|
18343
18470
|
|
|
18344
18471
|
class DelimitedToken extends Token {
|
|
18345
|
-
constructor(kind,
|
|
18472
|
+
constructor(kind, [contentBegin, contentEnd], input, begin, end, trimLeft, trimRight, file) {
|
|
18346
18473
|
super(kind, input, begin, end, file);
|
|
18347
18474
|
this.trimLeft = false;
|
|
18348
18475
|
this.trimRight = false;
|
|
18349
|
-
|
|
18350
|
-
const
|
|
18351
|
-
|
|
18352
|
-
|
|
18353
|
-
|
|
18354
|
-
|
|
18476
|
+
const tl = input[contentBegin] === '-';
|
|
18477
|
+
const tr = input[contentEnd - 1] === '-';
|
|
18478
|
+
let l = tl ? contentBegin + 1 : contentBegin;
|
|
18479
|
+
let r = tr ? contentEnd - 1 : contentEnd;
|
|
18480
|
+
while (l < r && (TYPES[input.charCodeAt(l)] & BLANK))
|
|
18481
|
+
l++;
|
|
18482
|
+
while (r > l && (TYPES[input.charCodeAt(r - 1)] & BLANK))
|
|
18483
|
+
r--;
|
|
18484
|
+
this.contentRange = [l, r];
|
|
18355
18485
|
this.trimLeft = tl || trimLeft;
|
|
18356
18486
|
this.trimRight = tr || trimRight;
|
|
18357
18487
|
}
|
|
18488
|
+
get content() {
|
|
18489
|
+
return this.input.slice(this.contentRange[0], this.contentRange[1]);
|
|
18490
|
+
}
|
|
18358
18491
|
}
|
|
18359
18492
|
|
|
18360
18493
|
class TagToken extends DelimitedToken {
|
|
18361
18494
|
constructor(input, begin, end, options, file) {
|
|
18362
18495
|
const { trimTagLeft, trimTagRight, tagDelimiterLeft, tagDelimiterRight } = options;
|
|
18363
|
-
const
|
|
18364
|
-
super(TokenKind.Tag,
|
|
18365
|
-
|
|
18366
|
-
this.name = tokenizer.readTagName();
|
|
18367
|
-
|
|
18368
|
-
|
|
18369
|
-
|
|
18370
|
-
|
|
18496
|
+
const [valueBegin, valueEnd] = [begin + tagDelimiterLeft.length, end - tagDelimiterRight.length];
|
|
18497
|
+
super(TokenKind.Tag, [valueBegin, valueEnd], input, begin, end, trimTagLeft, trimTagRight, file);
|
|
18498
|
+
this.tokenizer = new Tokenizer(input, options.operators, file, this.contentRange);
|
|
18499
|
+
this.name = this.tokenizer.readTagName();
|
|
18500
|
+
this.tokenizer.assert(this.name, `illegal tag syntax, tag name expected`);
|
|
18501
|
+
this.tokenizer.skipBlank();
|
|
18502
|
+
}
|
|
18503
|
+
get args() {
|
|
18504
|
+
return this.tokenizer.input.slice(this.tokenizer.p, this.contentRange[1]);
|
|
18371
18505
|
}
|
|
18372
18506
|
}
|
|
18373
18507
|
|
|
18374
18508
|
class OutputToken extends DelimitedToken {
|
|
18375
18509
|
constructor(input, begin, end, options, file) {
|
|
18376
18510
|
const { trimOutputLeft, trimOutputRight, outputDelimiterLeft, outputDelimiterRight } = options;
|
|
18377
|
-
const
|
|
18378
|
-
super(TokenKind.Output,
|
|
18511
|
+
const valueRange = [begin + outputDelimiterLeft.length, end - outputDelimiterRight.length];
|
|
18512
|
+
super(TokenKind.Output, valueRange, input, begin, end, trimOutputLeft, trimOutputRight, file);
|
|
18379
18513
|
}
|
|
18380
18514
|
}
|
|
18381
18515
|
|
|
@@ -18395,10 +18529,13 @@ class HTMLToken extends Token {
|
|
|
18395
18529
|
}
|
|
18396
18530
|
|
|
18397
18531
|
class NumberToken extends Token {
|
|
18398
|
-
constructor(
|
|
18399
|
-
super(TokenKind.Number,
|
|
18400
|
-
this.
|
|
18401
|
-
this.
|
|
18532
|
+
constructor(input, begin, end, file) {
|
|
18533
|
+
super(TokenKind.Number, input, begin, end, file);
|
|
18534
|
+
this.input = input;
|
|
18535
|
+
this.begin = begin;
|
|
18536
|
+
this.end = end;
|
|
18537
|
+
this.file = file;
|
|
18538
|
+
this.content = Number(this.getText());
|
|
18402
18539
|
}
|
|
18403
18540
|
}
|
|
18404
18541
|
|
|
@@ -18411,16 +18548,6 @@ class IdentifierToken extends Token {
|
|
|
18411
18548
|
this.file = file;
|
|
18412
18549
|
this.content = this.getText();
|
|
18413
18550
|
}
|
|
18414
|
-
isNumber(allowSign = false) {
|
|
18415
|
-
const begin = allowSign && TYPES[this.input.charCodeAt(this.begin)] & SIGN
|
|
18416
|
-
? this.begin + 1
|
|
18417
|
-
: this.begin;
|
|
18418
|
-
for (let i = begin; i < this.end; i++) {
|
|
18419
|
-
if (!(TYPES[this.input.charCodeAt(i)] & NUMBER))
|
|
18420
|
-
return false;
|
|
18421
|
-
}
|
|
18422
|
-
return true;
|
|
18423
|
-
}
|
|
18424
18551
|
}
|
|
18425
18552
|
|
|
18426
18553
|
class LiteralToken extends Token {
|
|
@@ -18431,6 +18558,7 @@ class LiteralToken extends Token {
|
|
|
18431
18558
|
this.end = end;
|
|
18432
18559
|
this.file = file;
|
|
18433
18560
|
this.literal = this.getText();
|
|
18561
|
+
this.content = literalValues[this.literal];
|
|
18434
18562
|
}
|
|
18435
18563
|
}
|
|
18436
18564
|
|
|
@@ -18474,13 +18602,10 @@ class OperatorToken extends Token {
|
|
|
18474
18602
|
}
|
|
18475
18603
|
|
|
18476
18604
|
class PropertyAccessToken extends Token {
|
|
18477
|
-
constructor(variable, props, end) {
|
|
18478
|
-
super(TokenKind.PropertyAccess,
|
|
18605
|
+
constructor(variable, props, input, begin, end, file) {
|
|
18606
|
+
super(TokenKind.PropertyAccess, input, begin, end, file);
|
|
18479
18607
|
this.variable = variable;
|
|
18480
18608
|
this.props = props;
|
|
18481
|
-
this.propertyName = this.variable instanceof IdentifierToken
|
|
18482
|
-
? this.variable.getText()
|
|
18483
|
-
: parseStringLiteral(this.variable.getText());
|
|
18484
18609
|
}
|
|
18485
18610
|
}
|
|
18486
18611
|
|
|
@@ -18504,6 +18629,59 @@ class HashToken extends Token {
|
|
|
18504
18629
|
}
|
|
18505
18630
|
}
|
|
18506
18631
|
|
|
18632
|
+
const rHex = /[\da-fA-F]/;
|
|
18633
|
+
const rOct = /[0-7]/;
|
|
18634
|
+
const escapeChar = {
|
|
18635
|
+
b: '\b',
|
|
18636
|
+
f: '\f',
|
|
18637
|
+
n: '\n',
|
|
18638
|
+
r: '\r',
|
|
18639
|
+
t: '\t',
|
|
18640
|
+
v: '\x0B'
|
|
18641
|
+
};
|
|
18642
|
+
function hexVal(c) {
|
|
18643
|
+
const code = c.charCodeAt(0);
|
|
18644
|
+
if (code >= 97)
|
|
18645
|
+
return code - 87;
|
|
18646
|
+
if (code >= 65)
|
|
18647
|
+
return code - 55;
|
|
18648
|
+
return code - 48;
|
|
18649
|
+
}
|
|
18650
|
+
function parseStringLiteral(str) {
|
|
18651
|
+
let ret = '';
|
|
18652
|
+
for (let i = 1; i < str.length - 1; i++) {
|
|
18653
|
+
if (str[i] !== '\\') {
|
|
18654
|
+
ret += str[i];
|
|
18655
|
+
continue;
|
|
18656
|
+
}
|
|
18657
|
+
if (escapeChar[str[i + 1]] !== undefined) {
|
|
18658
|
+
ret += escapeChar[str[++i]];
|
|
18659
|
+
}
|
|
18660
|
+
else if (str[i + 1] === 'u') {
|
|
18661
|
+
let val = 0;
|
|
18662
|
+
let j = i + 2;
|
|
18663
|
+
while (j <= i + 5 && rHex.test(str[j])) {
|
|
18664
|
+
val = val * 16 + hexVal(str[j++]);
|
|
18665
|
+
}
|
|
18666
|
+
i = j - 1;
|
|
18667
|
+
ret += String.fromCharCode(val);
|
|
18668
|
+
}
|
|
18669
|
+
else if (!rOct.test(str[i + 1])) {
|
|
18670
|
+
ret += str[++i];
|
|
18671
|
+
}
|
|
18672
|
+
else {
|
|
18673
|
+
let j = i + 1;
|
|
18674
|
+
let val = 0;
|
|
18675
|
+
while (j <= i + 3 && rOct.test(str[j])) {
|
|
18676
|
+
val = val * 8 + hexVal(str[j++]);
|
|
18677
|
+
}
|
|
18678
|
+
i = j - 1;
|
|
18679
|
+
ret += String.fromCharCode(val);
|
|
18680
|
+
}
|
|
18681
|
+
}
|
|
18682
|
+
return ret;
|
|
18683
|
+
}
|
|
18684
|
+
|
|
18507
18685
|
class QuotedToken extends Token {
|
|
18508
18686
|
constructor(input, begin, end, file) {
|
|
18509
18687
|
super(TokenKind.Quoted, input, begin, end, file);
|
|
@@ -18511,6 +18689,7 @@ class QuotedToken extends Token {
|
|
|
18511
18689
|
this.begin = begin;
|
|
18512
18690
|
this.end = end;
|
|
18513
18691
|
this.file = file;
|
|
18692
|
+
this.content = parseStringLiteral(this.getText());
|
|
18514
18693
|
}
|
|
18515
18694
|
}
|
|
18516
18695
|
|
|
@@ -18526,26 +18705,48 @@ class RangeToken extends Token {
|
|
|
18526
18705
|
}
|
|
18527
18706
|
}
|
|
18528
18707
|
|
|
18708
|
+
/**
|
|
18709
|
+
* LiquidTagToken is different from TagToken by not having delimiters `{%` or `%}`
|
|
18710
|
+
*/
|
|
18529
18711
|
class LiquidTagToken extends DelimitedToken {
|
|
18530
18712
|
constructor(input, begin, end, options, file) {
|
|
18531
|
-
|
|
18532
|
-
|
|
18533
|
-
|
|
18534
|
-
|
|
18535
|
-
|
|
18536
|
-
|
|
18537
|
-
|
|
18538
|
-
|
|
18539
|
-
|
|
18540
|
-
|
|
18541
|
-
|
|
18542
|
-
|
|
18543
|
-
|
|
18544
|
-
|
|
18545
|
-
|
|
18713
|
+
super(TokenKind.Tag, [begin, end], input, begin, end, false, false, file);
|
|
18714
|
+
this.tokenizer = new Tokenizer(input, options.operators, file, this.contentRange);
|
|
18715
|
+
this.name = this.tokenizer.readTagName();
|
|
18716
|
+
this.tokenizer.assert(this.name, 'illegal liquid tag syntax');
|
|
18717
|
+
this.tokenizer.skipBlank();
|
|
18718
|
+
}
|
|
18719
|
+
get args() {
|
|
18720
|
+
return this.tokenizer.input.slice(this.tokenizer.p, this.contentRange[1]);
|
|
18721
|
+
}
|
|
18722
|
+
}
|
|
18723
|
+
|
|
18724
|
+
/**
|
|
18725
|
+
* value expression with optional filters
|
|
18726
|
+
* e.g.
|
|
18727
|
+
* {% assign foo="bar" | append: "coo" %}
|
|
18728
|
+
*/
|
|
18729
|
+
class FilteredValueToken extends Token {
|
|
18730
|
+
constructor(initial, filters, input, begin, end, file) {
|
|
18731
|
+
super(TokenKind.FilteredValue, input, begin, end, file);
|
|
18732
|
+
this.initial = initial;
|
|
18733
|
+
this.filters = filters;
|
|
18734
|
+
this.input = input;
|
|
18735
|
+
this.begin = begin;
|
|
18736
|
+
this.end = end;
|
|
18737
|
+
this.file = file;
|
|
18546
18738
|
}
|
|
18547
18739
|
}
|
|
18548
18740
|
|
|
18741
|
+
const polyfill = {
|
|
18742
|
+
now: () => Date.now()
|
|
18743
|
+
};
|
|
18744
|
+
function getPerformance() {
|
|
18745
|
+
return (typeof global === 'object' && global.performance) ||
|
|
18746
|
+
(typeof window === 'object' && window.performance) ||
|
|
18747
|
+
polyfill;
|
|
18748
|
+
}
|
|
18749
|
+
|
|
18549
18750
|
class SimpleEmitter {
|
|
18550
18751
|
constructor() {
|
|
18551
18752
|
this.buffer = '';
|
|
@@ -18601,20 +18802,28 @@ class Render {
|
|
|
18601
18802
|
if (!emitter) {
|
|
18602
18803
|
emitter = ctx.opts.keepOutputType ? new KeepingTypeEmitter() : new SimpleEmitter();
|
|
18603
18804
|
}
|
|
18805
|
+
const errors = [];
|
|
18604
18806
|
for (const tpl of templates) {
|
|
18807
|
+
ctx.renderLimit.check(getPerformance().now());
|
|
18605
18808
|
try {
|
|
18606
18809
|
// if tpl.render supports emitter, it'll return empty `html`
|
|
18607
18810
|
const html = yield tpl.render(ctx, emitter);
|
|
18608
18811
|
// if not, it'll return an `html`, write to the emitter for it
|
|
18609
18812
|
html && emitter.write(html);
|
|
18610
|
-
if (
|
|
18813
|
+
if (ctx.breakCalled || ctx.continueCalled)
|
|
18611
18814
|
break;
|
|
18612
18815
|
}
|
|
18613
18816
|
catch (e) {
|
|
18614
|
-
const err =
|
|
18615
|
-
|
|
18817
|
+
const err = LiquidError.is(e) ? e : new RenderError(e, tpl);
|
|
18818
|
+
if (ctx.opts.catchAllErrors)
|
|
18819
|
+
errors.push(err);
|
|
18820
|
+
else
|
|
18821
|
+
throw err;
|
|
18616
18822
|
}
|
|
18617
18823
|
}
|
|
18824
|
+
if (errors.length) {
|
|
18825
|
+
throw new LiquidErrors(errors);
|
|
18826
|
+
}
|
|
18618
18827
|
return emitter.buffer;
|
|
18619
18828
|
}
|
|
18620
18829
|
}
|
|
@@ -18640,25 +18849,24 @@ class Expression {
|
|
|
18640
18849
|
operands.push(result);
|
|
18641
18850
|
}
|
|
18642
18851
|
else {
|
|
18643
|
-
operands.push(yield evalToken(token, ctx, lenient
|
|
18852
|
+
operands.push(yield evalToken(token, ctx, lenient));
|
|
18644
18853
|
}
|
|
18645
18854
|
}
|
|
18646
18855
|
return operands[0];
|
|
18647
18856
|
}
|
|
18857
|
+
valid() {
|
|
18858
|
+
return !!this.postfix.length;
|
|
18859
|
+
}
|
|
18648
18860
|
}
|
|
18649
18861
|
function* evalToken(token, ctx, lenient = false) {
|
|
18862
|
+
if (!token)
|
|
18863
|
+
return;
|
|
18864
|
+
if ('content' in token)
|
|
18865
|
+
return token.content;
|
|
18650
18866
|
if (isPropertyAccessToken(token))
|
|
18651
18867
|
return yield evalPropertyAccessToken(token, ctx, lenient);
|
|
18652
18868
|
if (isRangeToken(token))
|
|
18653
18869
|
return yield evalRangeToken(token, ctx);
|
|
18654
|
-
if (isLiteralToken(token))
|
|
18655
|
-
return evalLiteralToken(token);
|
|
18656
|
-
if (isNumberToken(token))
|
|
18657
|
-
return evalNumberToken(token);
|
|
18658
|
-
if (isWordToken(token))
|
|
18659
|
-
return token.getText();
|
|
18660
|
-
if (isQuotedToken(token))
|
|
18661
|
-
return evalQuotedToken(token);
|
|
18662
18870
|
}
|
|
18663
18871
|
function* evalPropertyAccessToken(token, ctx, lenient) {
|
|
18664
18872
|
const props = [];
|
|
@@ -18666,7 +18874,13 @@ function* evalPropertyAccessToken(token, ctx, lenient) {
|
|
|
18666
18874
|
props.push((yield evalToken(prop, ctx, false)));
|
|
18667
18875
|
}
|
|
18668
18876
|
try {
|
|
18669
|
-
|
|
18877
|
+
if (token.variable) {
|
|
18878
|
+
const variable = yield evalToken(token.variable, ctx, lenient);
|
|
18879
|
+
return yield ctx._getFromScope(variable, props);
|
|
18880
|
+
}
|
|
18881
|
+
else {
|
|
18882
|
+
return yield ctx._get(props);
|
|
18883
|
+
}
|
|
18670
18884
|
}
|
|
18671
18885
|
catch (e) {
|
|
18672
18886
|
if (lenient && e.name === 'InternalUndefinedVariableError')
|
|
@@ -18674,19 +18888,13 @@ function* evalPropertyAccessToken(token, ctx, lenient) {
|
|
|
18674
18888
|
throw (new UndefinedVariableError(e, token));
|
|
18675
18889
|
}
|
|
18676
18890
|
}
|
|
18677
|
-
function evalNumberToken(token) {
|
|
18678
|
-
const str = token.whole.content + '.' + (token.decimal ? token.decimal.content : '');
|
|
18679
|
-
return Number(str);
|
|
18680
|
-
}
|
|
18681
18891
|
function evalQuotedToken(token) {
|
|
18682
|
-
return
|
|
18683
|
-
}
|
|
18684
|
-
function evalLiteralToken(token) {
|
|
18685
|
-
return literalValues[token.literal];
|
|
18892
|
+
return token.content;
|
|
18686
18893
|
}
|
|
18687
18894
|
function* evalRangeToken(token, ctx) {
|
|
18688
18895
|
const low = yield evalToken(token.lhs, ctx);
|
|
18689
18896
|
const high = yield evalToken(token.rhs, ctx);
|
|
18897
|
+
ctx.memoryLimit.use(high - low + 1);
|
|
18690
18898
|
return range(+low, +high + 1);
|
|
18691
18899
|
}
|
|
18692
18900
|
function* toPostfix(tokens) {
|
|
@@ -18710,6 +18918,7 @@ function isTruthy(val, ctx) {
|
|
|
18710
18918
|
return !isFalsy(val, ctx);
|
|
18711
18919
|
}
|
|
18712
18920
|
function isFalsy(val, ctx) {
|
|
18921
|
+
val = toValue(val);
|
|
18713
18922
|
if (ctx.opts.jsTruthy) {
|
|
18714
18923
|
return !val;
|
|
18715
18924
|
}
|
|
@@ -18719,8 +18928,8 @@ function isFalsy(val, ctx) {
|
|
|
18719
18928
|
}
|
|
18720
18929
|
|
|
18721
18930
|
const defaultOperators = {
|
|
18722
|
-
'==':
|
|
18723
|
-
'!=': (l, r) => !
|
|
18931
|
+
'==': equals,
|
|
18932
|
+
'!=': (l, r) => !equals(l, r),
|
|
18724
18933
|
'>': (l, r) => {
|
|
18725
18934
|
if (isComparable(l))
|
|
18726
18935
|
return l.gt(r);
|
|
@@ -18751,14 +18960,17 @@ const defaultOperators = {
|
|
|
18751
18960
|
},
|
|
18752
18961
|
'contains': (l, r) => {
|
|
18753
18962
|
l = toValue(l);
|
|
18754
|
-
|
|
18755
|
-
|
|
18963
|
+
if (isArray(l))
|
|
18964
|
+
return l.some((i) => equals(i, r));
|
|
18965
|
+
if (isFunction(l === null || l === void 0 ? void 0 : l.indexOf))
|
|
18966
|
+
return l.indexOf(toValue(r)) > -1;
|
|
18967
|
+
return false;
|
|
18756
18968
|
},
|
|
18757
18969
|
'not': (v, ctx) => isFalsy(toValue(v), ctx),
|
|
18758
18970
|
'and': (l, r, ctx) => isTruthy(toValue(l), ctx) && isTruthy(toValue(r), ctx),
|
|
18759
18971
|
'or': (l, r, ctx) => isTruthy(toValue(l), ctx) || isTruthy(toValue(r), ctx)
|
|
18760
18972
|
};
|
|
18761
|
-
function
|
|
18973
|
+
function equals(lhs, rhs) {
|
|
18762
18974
|
if (isComparable(lhs))
|
|
18763
18975
|
return lhs.equals(rhs);
|
|
18764
18976
|
if (isComparable(rhs))
|
|
@@ -18766,14 +18978,17 @@ function equal(lhs, rhs) {
|
|
|
18766
18978
|
lhs = toValue(lhs);
|
|
18767
18979
|
rhs = toValue(rhs);
|
|
18768
18980
|
if (isArray(lhs)) {
|
|
18769
|
-
return isArray(rhs) &&
|
|
18981
|
+
return isArray(rhs) && arrayEquals(lhs, rhs);
|
|
18770
18982
|
}
|
|
18771
18983
|
return lhs === rhs;
|
|
18772
18984
|
}
|
|
18773
|
-
function
|
|
18985
|
+
function arrayEquals(lhs, rhs) {
|
|
18774
18986
|
if (lhs.length !== rhs.length)
|
|
18775
18987
|
return false;
|
|
18776
|
-
return !lhs.some((value, i) => !
|
|
18988
|
+
return !lhs.some((value, i) => !equals(value, rhs[i]));
|
|
18989
|
+
}
|
|
18990
|
+
function arrayIncludes(arr, item) {
|
|
18991
|
+
return arr.some(value => equals(value, item));
|
|
18777
18992
|
}
|
|
18778
18993
|
|
|
18779
18994
|
class Node {
|
|
@@ -18834,7 +19049,10 @@ class LRU {
|
|
|
18834
19049
|
}
|
|
18835
19050
|
}
|
|
18836
19051
|
|
|
18837
|
-
|
|
19052
|
+
function requireResolve (file) {
|
|
19053
|
+
const require = module$1.createRequire(process.cwd() + '/');
|
|
19054
|
+
return require.resolve(file)
|
|
19055
|
+
}
|
|
18838
19056
|
|
|
18839
19057
|
const statAsync = promisify(require$$6.stat);
|
|
18840
19058
|
const readFileAsync = promisify(require$$6.readFile);
|
|
@@ -18897,7 +19115,7 @@ var fs = /*#__PURE__*/Object.freeze({
|
|
|
18897
19115
|
sep: require$$1$1.sep
|
|
18898
19116
|
});
|
|
18899
19117
|
|
|
18900
|
-
function
|
|
19118
|
+
function defaultFilter(value, defaultValue, ...args) {
|
|
18901
19119
|
value = toValue(value);
|
|
18902
19120
|
if (isArray(value) || isString(value))
|
|
18903
19121
|
return value.length ? value : defaultValue;
|
|
@@ -18908,9 +19126,34 @@ function Default(value, defaultValue, ...args) {
|
|
|
18908
19126
|
function json(value, space = 0) {
|
|
18909
19127
|
return JSON.stringify(value, null, space);
|
|
18910
19128
|
}
|
|
19129
|
+
function inspect(value, space = 0) {
|
|
19130
|
+
const ancestors = [];
|
|
19131
|
+
return JSON.stringify(value, function (_key, value) {
|
|
19132
|
+
if (typeof value !== 'object' || value === null)
|
|
19133
|
+
return value;
|
|
19134
|
+
// `this` is the object that value is contained in, i.e., its direct parent.
|
|
19135
|
+
while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this)
|
|
19136
|
+
ancestors.pop();
|
|
19137
|
+
if (ancestors.includes(value))
|
|
19138
|
+
return '[Circular]';
|
|
19139
|
+
ancestors.push(value);
|
|
19140
|
+
return value;
|
|
19141
|
+
}, space);
|
|
19142
|
+
}
|
|
19143
|
+
function to_integer(value) {
|
|
19144
|
+
return Number(value);
|
|
19145
|
+
}
|
|
18911
19146
|
const raw = {
|
|
18912
19147
|
raw: true,
|
|
18913
19148
|
handler: identify
|
|
19149
|
+
};
|
|
19150
|
+
var misc = {
|
|
19151
|
+
default: defaultFilter,
|
|
19152
|
+
raw,
|
|
19153
|
+
jsonify: json,
|
|
19154
|
+
to_integer,
|
|
19155
|
+
json,
|
|
19156
|
+
inspect
|
|
18914
19157
|
};
|
|
18915
19158
|
|
|
18916
19159
|
const escapeMap = {
|
|
@@ -18928,41 +19171,103 @@ const unescapeMap = {
|
|
|
18928
19171
|
''': "'"
|
|
18929
19172
|
};
|
|
18930
19173
|
function escape(str) {
|
|
18931
|
-
|
|
19174
|
+
str = stringify(str);
|
|
19175
|
+
this.context.memoryLimit.use(str.length);
|
|
19176
|
+
return str.replace(/&|<|>|"|'/g, m => escapeMap[m]);
|
|
19177
|
+
}
|
|
19178
|
+
function xml_escape(str) {
|
|
19179
|
+
return escape.call(this, str);
|
|
18932
19180
|
}
|
|
18933
19181
|
function unescape$1(str) {
|
|
18934
|
-
|
|
19182
|
+
str = stringify(str);
|
|
19183
|
+
this.context.memoryLimit.use(str.length);
|
|
19184
|
+
return str.replace(/&(amp|lt|gt|#34|#39);/g, m => unescapeMap[m]);
|
|
18935
19185
|
}
|
|
18936
19186
|
function escape_once(str) {
|
|
18937
|
-
return escape(unescape$1(
|
|
19187
|
+
return escape.call(this, unescape$1.call(this, str));
|
|
18938
19188
|
}
|
|
18939
19189
|
function newline_to_br(v) {
|
|
18940
|
-
|
|
19190
|
+
const str = stringify(v);
|
|
19191
|
+
this.context.memoryLimit.use(str.length);
|
|
19192
|
+
return str.replace(/\r?\n/gm, '<br />\n');
|
|
18941
19193
|
}
|
|
18942
19194
|
function strip_html(v) {
|
|
18943
|
-
|
|
19195
|
+
const str = stringify(v);
|
|
19196
|
+
this.context.memoryLimit.use(str.length);
|
|
19197
|
+
return str.replace(/<script[\s\S]*?<\/script>|<style[\s\S]*?<\/style>|<.*?>|<!--[\s\S]*?-->/g, '');
|
|
18944
19198
|
}
|
|
18945
19199
|
|
|
18946
19200
|
var htmlFilters = /*#__PURE__*/Object.freeze({
|
|
18947
19201
|
__proto__: null,
|
|
18948
19202
|
escape: escape,
|
|
19203
|
+
xml_escape: xml_escape,
|
|
18949
19204
|
escape_once: escape_once,
|
|
18950
19205
|
newline_to_br: newline_to_br,
|
|
18951
19206
|
strip_html: strip_html
|
|
18952
19207
|
});
|
|
18953
19208
|
|
|
19209
|
+
class MapFS {
|
|
19210
|
+
constructor(mapping) {
|
|
19211
|
+
this.mapping = mapping;
|
|
19212
|
+
this.sep = '/';
|
|
19213
|
+
}
|
|
19214
|
+
exists(filepath) {
|
|
19215
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19216
|
+
return this.existsSync(filepath);
|
|
19217
|
+
});
|
|
19218
|
+
}
|
|
19219
|
+
existsSync(filepath) {
|
|
19220
|
+
return !isNil(this.mapping[filepath]);
|
|
19221
|
+
}
|
|
19222
|
+
readFile(filepath) {
|
|
19223
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19224
|
+
return this.readFileSync(filepath);
|
|
19225
|
+
});
|
|
19226
|
+
}
|
|
19227
|
+
readFileSync(filepath) {
|
|
19228
|
+
const content = this.mapping[filepath];
|
|
19229
|
+
if (isNil(content))
|
|
19230
|
+
throw new Error(`ENOENT: ${filepath}`);
|
|
19231
|
+
return content;
|
|
19232
|
+
}
|
|
19233
|
+
dirname(filepath) {
|
|
19234
|
+
const segments = filepath.split(this.sep);
|
|
19235
|
+
segments.pop();
|
|
19236
|
+
return segments.join(this.sep);
|
|
19237
|
+
}
|
|
19238
|
+
resolve(dir, file, ext) {
|
|
19239
|
+
file += ext;
|
|
19240
|
+
if (dir === '.')
|
|
19241
|
+
return file;
|
|
19242
|
+
const segments = dir.split(/\/+/);
|
|
19243
|
+
for (const segment of file.split(this.sep)) {
|
|
19244
|
+
if (segment === '.' || segment === '')
|
|
19245
|
+
continue;
|
|
19246
|
+
else if (segment === '..') {
|
|
19247
|
+
if (segments.length > 1 || segments[0] !== '')
|
|
19248
|
+
segments.pop();
|
|
19249
|
+
}
|
|
19250
|
+
else
|
|
19251
|
+
segments.push(segment);
|
|
19252
|
+
}
|
|
19253
|
+
return segments.join(this.sep);
|
|
19254
|
+
}
|
|
19255
|
+
}
|
|
19256
|
+
|
|
18954
19257
|
const defaultOptions = {
|
|
18955
19258
|
root: ['.'],
|
|
18956
19259
|
layouts: ['.'],
|
|
18957
19260
|
partials: ['.'],
|
|
18958
19261
|
relativeReference: true,
|
|
18959
19262
|
jekyllInclude: false,
|
|
19263
|
+
keyValueSeparator: ':',
|
|
18960
19264
|
cache: undefined,
|
|
18961
19265
|
extname: '',
|
|
18962
19266
|
fs: fs,
|
|
18963
19267
|
dynamicPartials: true,
|
|
18964
19268
|
jsTruthy: false,
|
|
18965
19269
|
dateFormat: '%A, %B %-e, %Y at %-l:%M %P %z',
|
|
19270
|
+
locale: '',
|
|
18966
19271
|
trimTagRight: false,
|
|
18967
19272
|
trimTagLeft: false,
|
|
18968
19273
|
trimOutputRight: false,
|
|
@@ -18979,9 +19284,13 @@ const defaultOptions = {
|
|
|
18979
19284
|
lenientIf: false,
|
|
18980
19285
|
globals: {},
|
|
18981
19286
|
keepOutputType: false,
|
|
18982
|
-
operators: defaultOperators
|
|
19287
|
+
operators: defaultOperators,
|
|
19288
|
+
memoryLimit: Infinity,
|
|
19289
|
+
parseLimit: Infinity,
|
|
19290
|
+
renderLimit: Infinity
|
|
18983
19291
|
};
|
|
18984
19292
|
function normalize(options) {
|
|
19293
|
+
var _a, _b;
|
|
18985
19294
|
if (options.hasOwnProperty('root')) {
|
|
18986
19295
|
if (!options.hasOwnProperty('partials'))
|
|
18987
19296
|
options.partials = options.root;
|
|
@@ -19007,13 +19316,21 @@ function normalize(options) {
|
|
|
19007
19316
|
options.partials = normalizeDirectoryList(options.partials);
|
|
19008
19317
|
options.layouts = normalizeDirectoryList(options.layouts);
|
|
19009
19318
|
options.outputEscape = options.outputEscape && getOutputEscapeFunction(options.outputEscape);
|
|
19319
|
+
if (!options.locale) {
|
|
19320
|
+
options.locale = (_b = (_a = getDateTimeFormat()) === null || _a === void 0 ? void 0 : _a().resolvedOptions().locale) !== null && _b !== void 0 ? _b : 'en-US';
|
|
19321
|
+
}
|
|
19322
|
+
if (options.templates) {
|
|
19323
|
+
options.fs = new MapFS(options.templates);
|
|
19324
|
+
options.relativeReference = true;
|
|
19325
|
+
options.root = options.partials = options.layouts = '.';
|
|
19326
|
+
}
|
|
19010
19327
|
return options;
|
|
19011
19328
|
}
|
|
19012
19329
|
function getOutputEscapeFunction(nameOrFunction) {
|
|
19013
19330
|
if (nameOrFunction === 'escape')
|
|
19014
19331
|
return escape;
|
|
19015
19332
|
if (nameOrFunction === 'json')
|
|
19016
|
-
return json;
|
|
19333
|
+
return misc.json;
|
|
19017
19334
|
assert(isFunction(nameOrFunction), '`outputEscape` need to be of type string or function');
|
|
19018
19335
|
return nameOrFunction;
|
|
19019
19336
|
}
|
|
@@ -19026,22 +19343,6 @@ function normalizeDirectoryList(value) {
|
|
|
19026
19343
|
return list;
|
|
19027
19344
|
}
|
|
19028
19345
|
|
|
19029
|
-
function matchOperator(str, begin, trie, end = str.length) {
|
|
19030
|
-
let node = trie;
|
|
19031
|
-
let i = begin;
|
|
19032
|
-
let info;
|
|
19033
|
-
while (node[str[i]] && i < end) {
|
|
19034
|
-
node = node[str[i++]];
|
|
19035
|
-
if (node['end'])
|
|
19036
|
-
info = node;
|
|
19037
|
-
}
|
|
19038
|
-
if (!info)
|
|
19039
|
-
return -1;
|
|
19040
|
-
if (info['needBoundary'] && (TYPES[str.charCodeAt(i)] & IDENTIFIER))
|
|
19041
|
-
return -1;
|
|
19042
|
-
return i;
|
|
19043
|
-
}
|
|
19044
|
-
|
|
19045
19346
|
function whiteSpaceCtrl(tokens, options) {
|
|
19046
19347
|
let inRaw = false;
|
|
19047
19348
|
for (let i = 0; i < tokens.length; i++) {
|
|
@@ -19080,13 +19381,14 @@ function trimRight(token, greedy) {
|
|
|
19080
19381
|
}
|
|
19081
19382
|
|
|
19082
19383
|
class Tokenizer {
|
|
19083
|
-
constructor(input, operators = defaultOptions.operators, file) {
|
|
19384
|
+
constructor(input, operators = defaultOptions.operators, file, range) {
|
|
19084
19385
|
this.input = input;
|
|
19085
19386
|
this.file = file;
|
|
19086
|
-
this.p = 0;
|
|
19087
19387
|
this.rawBeginAt = -1;
|
|
19088
|
-
this.
|
|
19388
|
+
this.p = range ? range[0] : 0;
|
|
19389
|
+
this.N = range ? range[1] : input.length;
|
|
19089
19390
|
this.opTrie = createTrie(operators);
|
|
19391
|
+
this.literalTrie = createTrie(literalValues);
|
|
19090
19392
|
}
|
|
19091
19393
|
readExpression() {
|
|
19092
19394
|
return new Expression(this.readExpressionTokens());
|
|
@@ -19108,11 +19410,33 @@ class Tokenizer {
|
|
|
19108
19410
|
}
|
|
19109
19411
|
readOperator() {
|
|
19110
19412
|
this.skipBlank();
|
|
19111
|
-
const end =
|
|
19413
|
+
const end = this.matchTrie(this.opTrie);
|
|
19112
19414
|
if (end === -1)
|
|
19113
19415
|
return;
|
|
19114
19416
|
return new OperatorToken(this.input, this.p, (this.p = end), this.file);
|
|
19115
19417
|
}
|
|
19418
|
+
matchTrie(trie) {
|
|
19419
|
+
let node = trie;
|
|
19420
|
+
let i = this.p;
|
|
19421
|
+
let info;
|
|
19422
|
+
while (node[this.input[i]] && i < this.N) {
|
|
19423
|
+
node = node[this.input[i++]];
|
|
19424
|
+
if (node['end'])
|
|
19425
|
+
info = node;
|
|
19426
|
+
}
|
|
19427
|
+
if (!info)
|
|
19428
|
+
return -1;
|
|
19429
|
+
if (info['needBoundary'] && isWord(this.peek(i - this.p)))
|
|
19430
|
+
return -1;
|
|
19431
|
+
return i;
|
|
19432
|
+
}
|
|
19433
|
+
readFilteredValue() {
|
|
19434
|
+
const begin = this.p;
|
|
19435
|
+
const initial = this.readExpression();
|
|
19436
|
+
this.assert(initial.valid(), `invalid value expression: ${this.snapshot()}`);
|
|
19437
|
+
const filters = this.readFilters();
|
|
19438
|
+
return new FilteredValueToken(initial, filters, this.input, begin, this.p, this.file);
|
|
19439
|
+
}
|
|
19116
19440
|
readFilters() {
|
|
19117
19441
|
const filters = [];
|
|
19118
19442
|
while (true) {
|
|
@@ -19126,12 +19450,12 @@ class Tokenizer {
|
|
|
19126
19450
|
this.skipBlank();
|
|
19127
19451
|
if (this.end())
|
|
19128
19452
|
return null;
|
|
19129
|
-
assert(this.
|
|
19130
|
-
this.p++;
|
|
19131
|
-
const begin = this.p;
|
|
19453
|
+
this.assert(this.read() === '|', `expected "|" before filter`);
|
|
19132
19454
|
const name = this.readIdentifier();
|
|
19133
|
-
if (!name.size())
|
|
19455
|
+
if (!name.size()) {
|
|
19456
|
+
this.assert(this.end(), `expected filter name`);
|
|
19134
19457
|
return null;
|
|
19458
|
+
}
|
|
19135
19459
|
const args = [];
|
|
19136
19460
|
this.skipBlank();
|
|
19137
19461
|
if (this.peek() === ':') {
|
|
@@ -19140,10 +19464,14 @@ class Tokenizer {
|
|
|
19140
19464
|
const arg = this.readFilterArg();
|
|
19141
19465
|
arg && args.push(arg);
|
|
19142
19466
|
this.skipBlank();
|
|
19143
|
-
assert(this.end() || this.peek() === ',' || this.peek() === '|', () => `unexpected character ${this.snapshot()}`);
|
|
19467
|
+
this.assert(this.end() || this.peek() === ',' || this.peek() === '|', () => `unexpected character ${this.snapshot()}`);
|
|
19144
19468
|
} while (this.peek() === ',');
|
|
19145
19469
|
}
|
|
19146
|
-
|
|
19470
|
+
else if (this.peek() === '|' || this.end()) ;
|
|
19471
|
+
else {
|
|
19472
|
+
throw this.error('expected ":" after filter name');
|
|
19473
|
+
}
|
|
19474
|
+
return new FilterToken(name.getText(), args, this.input, name.begin, this.p, this.file);
|
|
19147
19475
|
}
|
|
19148
19476
|
readFilterArg() {
|
|
19149
19477
|
const key = this.readValue();
|
|
@@ -19184,20 +19512,21 @@ class Tokenizer {
|
|
|
19184
19512
|
}
|
|
19185
19513
|
return new HTMLToken(this.input, begin, this.p, this.file);
|
|
19186
19514
|
}
|
|
19187
|
-
readTagToken(options
|
|
19515
|
+
readTagToken(options) {
|
|
19188
19516
|
const { file, input } = this;
|
|
19189
19517
|
const begin = this.p;
|
|
19190
19518
|
if (this.readToDelimiter(options.tagDelimiterRight) === -1) {
|
|
19191
|
-
throw this.
|
|
19519
|
+
throw this.error(`tag ${this.snapshot(begin)} not closed`, begin);
|
|
19192
19520
|
}
|
|
19193
19521
|
const token = new TagToken(input, begin, this.p, options, file);
|
|
19194
19522
|
if (token.name === 'raw')
|
|
19195
19523
|
this.rawBeginAt = begin;
|
|
19196
19524
|
return token;
|
|
19197
19525
|
}
|
|
19198
|
-
readToDelimiter(delimiter) {
|
|
19526
|
+
readToDelimiter(delimiter, respectQuoted = false) {
|
|
19527
|
+
this.skipBlank();
|
|
19199
19528
|
while (this.p < this.N) {
|
|
19200
|
-
if ((this.peekType() & QUOTE)) {
|
|
19529
|
+
if (respectQuoted && (this.peekType() & QUOTE)) {
|
|
19201
19530
|
this.readQuoted();
|
|
19202
19531
|
continue;
|
|
19203
19532
|
}
|
|
@@ -19211,8 +19540,8 @@ class Tokenizer {
|
|
|
19211
19540
|
const { file, input } = this;
|
|
19212
19541
|
const { outputDelimiterRight } = options;
|
|
19213
19542
|
const begin = this.p;
|
|
19214
|
-
if (this.readToDelimiter(outputDelimiterRight) === -1) {
|
|
19215
|
-
throw this.
|
|
19543
|
+
if (this.readToDelimiter(outputDelimiterRight, true) === -1) {
|
|
19544
|
+
throw this.error(`output ${this.snapshot(begin)} not closed`, begin);
|
|
19216
19545
|
}
|
|
19217
19546
|
return new OutputToken(input, begin, this.p, options, file);
|
|
19218
19547
|
}
|
|
@@ -19242,30 +19571,34 @@ class Tokenizer {
|
|
|
19242
19571
|
this.p++;
|
|
19243
19572
|
}
|
|
19244
19573
|
}
|
|
19245
|
-
throw this.
|
|
19574
|
+
throw this.error(`raw ${this.snapshot(this.rawBeginAt)} not closed`, begin);
|
|
19246
19575
|
}
|
|
19247
19576
|
readLiquidTagTokens(options = defaultOptions) {
|
|
19248
19577
|
const tokens = [];
|
|
19249
19578
|
while (this.p < this.N) {
|
|
19250
19579
|
const token = this.readLiquidTagToken(options);
|
|
19251
|
-
|
|
19252
|
-
tokens.push(token);
|
|
19580
|
+
token && tokens.push(token);
|
|
19253
19581
|
}
|
|
19254
19582
|
return tokens;
|
|
19255
19583
|
}
|
|
19256
19584
|
readLiquidTagToken(options) {
|
|
19257
|
-
|
|
19585
|
+
this.skipBlank();
|
|
19586
|
+
if (this.end())
|
|
19587
|
+
return;
|
|
19258
19588
|
const begin = this.p;
|
|
19259
|
-
|
|
19260
|
-
|
|
19261
|
-
|
|
19262
|
-
return new LiquidTagToken(input, begin, end, options, file);
|
|
19589
|
+
this.readToDelimiter('\n');
|
|
19590
|
+
const end = this.p;
|
|
19591
|
+
return new LiquidTagToken(this.input, begin, end, options, this.file);
|
|
19263
19592
|
}
|
|
19264
|
-
|
|
19265
|
-
return new TokenizationError(msg, new IdentifierToken(this.input,
|
|
19593
|
+
error(msg, pos = this.p) {
|
|
19594
|
+
return new TokenizationError(msg, new IdentifierToken(this.input, pos, this.N, this.file));
|
|
19595
|
+
}
|
|
19596
|
+
assert(pred, msg, pos) {
|
|
19597
|
+
if (!pred)
|
|
19598
|
+
throw this.error(typeof msg === 'function' ? msg() : msg, pos);
|
|
19266
19599
|
}
|
|
19267
19600
|
snapshot(begin = this.p) {
|
|
19268
|
-
return JSON.stringify(ellipsis(this.input.slice(begin),
|
|
19601
|
+
return JSON.stringify(ellipsis(this.input.slice(begin, this.N), 32));
|
|
19269
19602
|
}
|
|
19270
19603
|
/**
|
|
19271
19604
|
* @deprecated use #readIdentifier instead
|
|
@@ -19276,10 +19609,14 @@ class Tokenizer {
|
|
|
19276
19609
|
readIdentifier() {
|
|
19277
19610
|
this.skipBlank();
|
|
19278
19611
|
const begin = this.p;
|
|
19279
|
-
while (this.
|
|
19612
|
+
while (!this.end() && isWord(this.peek()))
|
|
19280
19613
|
++this.p;
|
|
19281
19614
|
return new IdentifierToken(this.input, begin, this.p, this.file);
|
|
19282
19615
|
}
|
|
19616
|
+
readNonEmptyIdentifier() {
|
|
19617
|
+
const id = this.readIdentifier();
|
|
19618
|
+
return id.size() ? id : undefined;
|
|
19619
|
+
}
|
|
19283
19620
|
readTagName() {
|
|
19284
19621
|
this.skipBlank();
|
|
19285
19622
|
// Handle inline comment tags
|
|
@@ -19301,12 +19638,12 @@ class Tokenizer {
|
|
|
19301
19638
|
if (this.peek() === ',')
|
|
19302
19639
|
++this.p;
|
|
19303
19640
|
const begin = this.p;
|
|
19304
|
-
const name = this.
|
|
19305
|
-
if (!name
|
|
19641
|
+
const name = this.readNonEmptyIdentifier();
|
|
19642
|
+
if (!name)
|
|
19306
19643
|
return;
|
|
19307
19644
|
let value;
|
|
19308
19645
|
this.skipBlank();
|
|
19309
|
-
const sep = jekyllStyle ? '=' : ':';
|
|
19646
|
+
const sep = isString(jekyllStyle) ? jekyllStyle : (jekyllStyle ? '=' : ':');
|
|
19310
19647
|
if (this.peek() === sep) {
|
|
19311
19648
|
++this.p;
|
|
19312
19649
|
value = this.readValue();
|
|
@@ -19314,14 +19651,17 @@ class Tokenizer {
|
|
|
19314
19651
|
return new HashToken(this.input, begin, this.p, name, value, this.file);
|
|
19315
19652
|
}
|
|
19316
19653
|
remaining() {
|
|
19317
|
-
return this.input.slice(this.p);
|
|
19654
|
+
return this.input.slice(this.p, this.N);
|
|
19318
19655
|
}
|
|
19319
|
-
advance(
|
|
19320
|
-
this.p +=
|
|
19656
|
+
advance(step = 1) {
|
|
19657
|
+
this.p += step;
|
|
19321
19658
|
}
|
|
19322
19659
|
end() {
|
|
19323
19660
|
return this.p >= this.N;
|
|
19324
19661
|
}
|
|
19662
|
+
read() {
|
|
19663
|
+
return this.input[this.p++];
|
|
19664
|
+
}
|
|
19325
19665
|
readTo(end) {
|
|
19326
19666
|
while (this.p < this.N) {
|
|
19327
19667
|
++this.p;
|
|
@@ -19331,50 +19671,86 @@ class Tokenizer {
|
|
|
19331
19671
|
return -1;
|
|
19332
19672
|
}
|
|
19333
19673
|
readValue() {
|
|
19334
|
-
|
|
19335
|
-
|
|
19336
|
-
|
|
19337
|
-
|
|
19338
|
-
|
|
19339
|
-
|
|
19340
|
-
|
|
19341
|
-
|
|
19342
|
-
|
|
19343
|
-
|
|
19344
|
-
|
|
19345
|
-
|
|
19346
|
-
|
|
19347
|
-
|
|
19348
|
-
|
|
19349
|
-
|
|
19350
|
-
|
|
19674
|
+
this.skipBlank();
|
|
19675
|
+
const begin = this.p;
|
|
19676
|
+
const variable = this.readLiteral() || this.readQuoted() || this.readRange() || this.readNumber();
|
|
19677
|
+
const props = this.readProperties(!variable);
|
|
19678
|
+
if (!props.length)
|
|
19679
|
+
return variable;
|
|
19680
|
+
return new PropertyAccessToken(variable, props, this.input, begin, this.p);
|
|
19681
|
+
}
|
|
19682
|
+
readScopeValue() {
|
|
19683
|
+
this.skipBlank();
|
|
19684
|
+
const begin = this.p;
|
|
19685
|
+
const props = this.readProperties();
|
|
19686
|
+
if (!props.length)
|
|
19687
|
+
return undefined;
|
|
19688
|
+
return new PropertyAccessToken(undefined, props, this.input, begin, this.p);
|
|
19689
|
+
}
|
|
19690
|
+
readProperties(isBegin = true) {
|
|
19351
19691
|
const props = [];
|
|
19352
19692
|
while (true) {
|
|
19353
19693
|
if (this.peek() === '[') {
|
|
19354
|
-
isNumber = false;
|
|
19355
19694
|
this.p++;
|
|
19356
19695
|
const prop = this.readValue() || new IdentifierToken(this.input, this.p, this.p, this.file);
|
|
19357
|
-
this.readTo(']');
|
|
19696
|
+
this.assert(this.readTo(']') !== -1, '[ not closed');
|
|
19358
19697
|
props.push(prop);
|
|
19698
|
+
continue;
|
|
19699
|
+
}
|
|
19700
|
+
if (isBegin && !props.length) {
|
|
19701
|
+
const prop = this.readNonEmptyIdentifier();
|
|
19702
|
+
if (prop) {
|
|
19703
|
+
props.push(prop);
|
|
19704
|
+
continue;
|
|
19705
|
+
}
|
|
19359
19706
|
}
|
|
19360
|
-
|
|
19707
|
+
if (this.peek() === '.' && this.peek(1) !== '.') { // skip range syntax
|
|
19361
19708
|
this.p++;
|
|
19362
|
-
const prop = this.
|
|
19363
|
-
if (!prop
|
|
19709
|
+
const prop = this.readNonEmptyIdentifier();
|
|
19710
|
+
if (!prop)
|
|
19364
19711
|
break;
|
|
19365
|
-
if (!prop.isNumber())
|
|
19366
|
-
isNumber = false;
|
|
19367
19712
|
props.push(prop);
|
|
19713
|
+
continue;
|
|
19714
|
+
}
|
|
19715
|
+
break;
|
|
19716
|
+
}
|
|
19717
|
+
return props;
|
|
19718
|
+
}
|
|
19719
|
+
readNumber() {
|
|
19720
|
+
this.skipBlank();
|
|
19721
|
+
let decimalFound = false;
|
|
19722
|
+
let digitFound = false;
|
|
19723
|
+
let n = 0;
|
|
19724
|
+
if (this.peekType() & SIGN)
|
|
19725
|
+
n++;
|
|
19726
|
+
while (this.p + n <= this.N) {
|
|
19727
|
+
if (this.peekType(n) & NUMBER) {
|
|
19728
|
+
digitFound = true;
|
|
19729
|
+
n++;
|
|
19730
|
+
}
|
|
19731
|
+
else if (this.peek(n) === '.' && this.peek(n + 1) !== '.') {
|
|
19732
|
+
if (decimalFound || !digitFound)
|
|
19733
|
+
return;
|
|
19734
|
+
decimalFound = true;
|
|
19735
|
+
n++;
|
|
19368
19736
|
}
|
|
19369
19737
|
else
|
|
19370
19738
|
break;
|
|
19371
19739
|
}
|
|
19372
|
-
if (
|
|
19373
|
-
|
|
19740
|
+
if (digitFound && !isWord(this.peek(n))) {
|
|
19741
|
+
const num = new NumberToken(this.input, this.p, this.p + n, this.file);
|
|
19742
|
+
this.advance(n);
|
|
19743
|
+
return num;
|
|
19374
19744
|
}
|
|
19375
|
-
|
|
19376
|
-
|
|
19377
|
-
|
|
19745
|
+
}
|
|
19746
|
+
readLiteral() {
|
|
19747
|
+
this.skipBlank();
|
|
19748
|
+
const end = this.matchTrie(this.literalTrie);
|
|
19749
|
+
if (end === -1)
|
|
19750
|
+
return;
|
|
19751
|
+
const literal = new LiteralToken(this.input, this.p, end, this.file);
|
|
19752
|
+
this.p = end;
|
|
19753
|
+
return literal;
|
|
19378
19754
|
}
|
|
19379
19755
|
readRange() {
|
|
19380
19756
|
this.skipBlank();
|
|
@@ -19390,7 +19766,7 @@ class Tokenizer {
|
|
|
19390
19766
|
}
|
|
19391
19767
|
readValueOrThrow() {
|
|
19392
19768
|
const value = this.readValue();
|
|
19393
|
-
assert(value, () => `unexpected token ${this.snapshot()}, value expected`);
|
|
19769
|
+
this.assert(value, () => `unexpected token ${this.snapshot()}, value expected`);
|
|
19394
19770
|
return value;
|
|
19395
19771
|
}
|
|
19396
19772
|
readQuoted() {
|
|
@@ -19437,10 +19813,10 @@ class Tokenizer {
|
|
|
19437
19813
|
return true;
|
|
19438
19814
|
}
|
|
19439
19815
|
peekType(n = 0) {
|
|
19440
|
-
return TYPES[this.input.charCodeAt(this.p + n)];
|
|
19816
|
+
return this.p + n >= this.N ? 0 : TYPES[this.input.charCodeAt(this.p + n)];
|
|
19441
19817
|
}
|
|
19442
19818
|
peek(n = 0) {
|
|
19443
|
-
return this.input[this.p + n];
|
|
19819
|
+
return this.p + n >= this.N ? '' : this.input[this.p + n];
|
|
19444
19820
|
}
|
|
19445
19821
|
skipBlank() {
|
|
19446
19822
|
while (this.peekType() & BLANK)
|
|
@@ -19496,6 +19872,7 @@ class Tag extends TemplateImpl {
|
|
|
19496
19872
|
super(token);
|
|
19497
19873
|
this.name = token.name;
|
|
19498
19874
|
this.liquid = liquid;
|
|
19875
|
+
this.tokenizer = token.tokenizer;
|
|
19499
19876
|
}
|
|
19500
19877
|
}
|
|
19501
19878
|
|
|
@@ -19508,9 +19885,9 @@ class Tag extends TemplateImpl {
|
|
|
19508
19885
|
* hash['reversed'] === undefined
|
|
19509
19886
|
*/
|
|
19510
19887
|
class Hash {
|
|
19511
|
-
constructor(
|
|
19888
|
+
constructor(input, jekyllStyle) {
|
|
19512
19889
|
this.hash = {};
|
|
19513
|
-
const tokenizer = new Tokenizer(
|
|
19890
|
+
const tokenizer = input instanceof Tokenizer ? input : new Tokenizer(input, {});
|
|
19514
19891
|
for (const hash of tokenizer.readHashes(jekyllStyle)) {
|
|
19515
19892
|
this.hash[hash.name.content] = hash.value;
|
|
19516
19893
|
}
|
|
@@ -19533,7 +19910,7 @@ function createTagClass(options) {
|
|
|
19533
19910
|
}
|
|
19534
19911
|
}
|
|
19535
19912
|
*render(ctx, emitter) {
|
|
19536
|
-
const hash = (yield new Hash(this.token.args).render(ctx));
|
|
19913
|
+
const hash = (yield new Hash(this.token.args, ctx.opts.keyValueSeparator).render(ctx));
|
|
19537
19914
|
return yield options.render.call(this, ctx, emitter, hash);
|
|
19538
19915
|
}
|
|
19539
19916
|
};
|
|
@@ -19544,13 +19921,14 @@ function isKeyValuePair(arr) {
|
|
|
19544
19921
|
}
|
|
19545
19922
|
|
|
19546
19923
|
class Filter {
|
|
19547
|
-
constructor(
|
|
19548
|
-
this.
|
|
19924
|
+
constructor(token, options, liquid) {
|
|
19925
|
+
this.token = token;
|
|
19926
|
+
this.name = token.name;
|
|
19549
19927
|
this.handler = isFunction(options)
|
|
19550
19928
|
? options
|
|
19551
19929
|
: (isFunction(options === null || options === void 0 ? void 0 : options.handler) ? options.handler : identify);
|
|
19552
19930
|
this.raw = !isFunction(options) && !!(options === null || options === void 0 ? void 0 : options.raw);
|
|
19553
|
-
this.args = args;
|
|
19931
|
+
this.args = token.args;
|
|
19554
19932
|
this.liquid = liquid;
|
|
19555
19933
|
}
|
|
19556
19934
|
*render(value, context) {
|
|
@@ -19561,7 +19939,7 @@ class Filter {
|
|
|
19561
19939
|
else
|
|
19562
19940
|
argv.push(yield evalToken(arg, context));
|
|
19563
19941
|
}
|
|
19564
|
-
return this.handler.apply({ context, liquid: this.liquid }, [value, ...argv]);
|
|
19942
|
+
return yield this.handler.apply({ context, token: this.token, liquid: this.liquid }, [value, ...argv]);
|
|
19565
19943
|
}
|
|
19566
19944
|
}
|
|
19567
19945
|
|
|
@@ -19569,11 +19947,13 @@ class Value {
|
|
|
19569
19947
|
/**
|
|
19570
19948
|
* @param str the value to be valuated, eg.: "foobar" | truncate: 3
|
|
19571
19949
|
*/
|
|
19572
|
-
constructor(
|
|
19950
|
+
constructor(input, liquid) {
|
|
19573
19951
|
this.filters = [];
|
|
19574
|
-
const
|
|
19575
|
-
|
|
19576
|
-
|
|
19952
|
+
const token = typeof input === 'string'
|
|
19953
|
+
? new Tokenizer(input, liquid.options.operators).readFilteredValue()
|
|
19954
|
+
: input;
|
|
19955
|
+
this.initial = token.initial;
|
|
19956
|
+
this.filters = token.filters.map(token => new Filter(token, this.getFilter(liquid, token.name), liquid));
|
|
19577
19957
|
}
|
|
19578
19958
|
*value(ctx, lenient) {
|
|
19579
19959
|
lenient = lenient || (ctx.opts.lenientIf && this.filters.length > 0 && this.filters[0].name === 'default');
|
|
@@ -19594,17 +19974,22 @@ class Output extends TemplateImpl {
|
|
|
19594
19974
|
constructor(token, liquid) {
|
|
19595
19975
|
var _a;
|
|
19596
19976
|
super(token);
|
|
19597
|
-
|
|
19977
|
+
const tokenizer = new Tokenizer(token.input, liquid.options.operators, token.file, token.contentRange);
|
|
19978
|
+
this.value = new Value(tokenizer.readFilteredValue(), liquid);
|
|
19598
19979
|
const filters = this.value.filters;
|
|
19599
19980
|
const outputEscape = liquid.options.outputEscape;
|
|
19600
19981
|
if (!((_a = filters[filters.length - 1]) === null || _a === void 0 ? void 0 : _a.raw) && outputEscape) {
|
|
19601
|
-
|
|
19982
|
+
const token = new FilterToken(toString.call(outputEscape), [], '', 0, 0);
|
|
19983
|
+
filters.push(new Filter(token, outputEscape, liquid));
|
|
19602
19984
|
}
|
|
19603
19985
|
}
|
|
19604
19986
|
*render(ctx, emitter) {
|
|
19605
19987
|
const val = yield this.value.value(ctx, false);
|
|
19606
19988
|
emitter.write(val);
|
|
19607
19989
|
}
|
|
19990
|
+
*arguments() {
|
|
19991
|
+
yield this.value;
|
|
19992
|
+
}
|
|
19608
19993
|
}
|
|
19609
19994
|
|
|
19610
19995
|
class HTML extends TemplateImpl {
|
|
@@ -19617,6 +20002,336 @@ class HTML extends TemplateImpl {
|
|
|
19617
20002
|
}
|
|
19618
20003
|
}
|
|
19619
20004
|
|
|
20005
|
+
/**
|
|
20006
|
+
* A variable's segments and location, which can be coerced to a string.
|
|
20007
|
+
*/
|
|
20008
|
+
class Variable {
|
|
20009
|
+
constructor(segments, location) {
|
|
20010
|
+
this.segments = segments;
|
|
20011
|
+
this.location = location;
|
|
20012
|
+
}
|
|
20013
|
+
toString() {
|
|
20014
|
+
return segmentsString(this.segments, true);
|
|
20015
|
+
}
|
|
20016
|
+
/** Return this variable's segments as an array, possibly with nested arrays for nested paths. */
|
|
20017
|
+
toArray() {
|
|
20018
|
+
function* _visit(...segments) {
|
|
20019
|
+
for (const segment of segments) {
|
|
20020
|
+
if (segment instanceof Variable) {
|
|
20021
|
+
yield Array.from(_visit(...segment.segments));
|
|
20022
|
+
}
|
|
20023
|
+
else {
|
|
20024
|
+
yield segment;
|
|
20025
|
+
}
|
|
20026
|
+
}
|
|
20027
|
+
}
|
|
20028
|
+
return Array.from(_visit(...this.segments));
|
|
20029
|
+
}
|
|
20030
|
+
}
|
|
20031
|
+
/**
|
|
20032
|
+
* Group variables by the string representation of their root segment.
|
|
20033
|
+
*/
|
|
20034
|
+
class VariableMap {
|
|
20035
|
+
constructor() {
|
|
20036
|
+
this.map = new Map();
|
|
20037
|
+
}
|
|
20038
|
+
get(key) {
|
|
20039
|
+
const k = segmentsString([key.segments[0]]);
|
|
20040
|
+
if (!this.map.has(k)) {
|
|
20041
|
+
this.map.set(k, []);
|
|
20042
|
+
}
|
|
20043
|
+
return this.map.get(k);
|
|
20044
|
+
}
|
|
20045
|
+
has(key) {
|
|
20046
|
+
return this.map.has(segmentsString([key.segments[0]]));
|
|
20047
|
+
}
|
|
20048
|
+
push(variable) {
|
|
20049
|
+
this.get(variable).push(variable);
|
|
20050
|
+
}
|
|
20051
|
+
asObject() {
|
|
20052
|
+
return Object.fromEntries(this.map);
|
|
20053
|
+
}
|
|
20054
|
+
}
|
|
20055
|
+
const defaultStaticAnalysisOptions = {
|
|
20056
|
+
partials: true
|
|
20057
|
+
};
|
|
20058
|
+
function* _analyze(templates, partials, sync) {
|
|
20059
|
+
const variables = new VariableMap();
|
|
20060
|
+
const globals = new VariableMap();
|
|
20061
|
+
const locals = new VariableMap();
|
|
20062
|
+
const rootScope = new DummyScope(new Set());
|
|
20063
|
+
// Names of partial templates that we've already analyzed.
|
|
20064
|
+
const seen = new Set();
|
|
20065
|
+
function updateVariables(variable, scope) {
|
|
20066
|
+
variables.push(variable);
|
|
20067
|
+
const aliased = scope.alias(variable);
|
|
20068
|
+
if (aliased !== undefined) {
|
|
20069
|
+
const root = aliased.segments[0];
|
|
20070
|
+
// TODO: What if a a template renders a rendered template? Do we need scope.parent?
|
|
20071
|
+
if (isString(root) && !rootScope.has(root)) {
|
|
20072
|
+
globals.push(aliased);
|
|
20073
|
+
}
|
|
20074
|
+
}
|
|
20075
|
+
else {
|
|
20076
|
+
const root = variable.segments[0];
|
|
20077
|
+
if (isString(root) && !scope.has(root)) {
|
|
20078
|
+
globals.push(variable);
|
|
20079
|
+
}
|
|
20080
|
+
}
|
|
20081
|
+
// Recurse for nested Variables
|
|
20082
|
+
for (const segment of variable.segments) {
|
|
20083
|
+
if (segment instanceof Variable) {
|
|
20084
|
+
updateVariables(segment, scope);
|
|
20085
|
+
}
|
|
20086
|
+
}
|
|
20087
|
+
}
|
|
20088
|
+
function* visit(template, scope) {
|
|
20089
|
+
if (template.arguments) {
|
|
20090
|
+
for (const arg of template.arguments()) {
|
|
20091
|
+
for (const variable of extractVariables(arg)) {
|
|
20092
|
+
updateVariables(variable, scope);
|
|
20093
|
+
}
|
|
20094
|
+
}
|
|
20095
|
+
}
|
|
20096
|
+
if (template.localScope) {
|
|
20097
|
+
for (const ident of template.localScope()) {
|
|
20098
|
+
scope.add(ident.content);
|
|
20099
|
+
scope.deleteAlias(ident.content);
|
|
20100
|
+
const [row, col] = ident.getPosition();
|
|
20101
|
+
locals.push(new Variable([ident.content], { row, col, file: ident.file }));
|
|
20102
|
+
}
|
|
20103
|
+
}
|
|
20104
|
+
if (template.children) {
|
|
20105
|
+
if (template.partialScope) {
|
|
20106
|
+
const partial = template.partialScope();
|
|
20107
|
+
if (partial === undefined) {
|
|
20108
|
+
// Layouts, for example, can have children that are not partials.
|
|
20109
|
+
for (const child of (yield template.children(partials, sync))) {
|
|
20110
|
+
yield visit(child, scope);
|
|
20111
|
+
}
|
|
20112
|
+
return;
|
|
20113
|
+
}
|
|
20114
|
+
if (seen.has(partial.name))
|
|
20115
|
+
return;
|
|
20116
|
+
const partialScopeNames = new Set();
|
|
20117
|
+
const partialScope = partial.isolated
|
|
20118
|
+
? new DummyScope(partialScopeNames)
|
|
20119
|
+
: scope.push(partialScopeNames);
|
|
20120
|
+
for (const name of partial.scope) {
|
|
20121
|
+
if (isString(name)) {
|
|
20122
|
+
partialScopeNames.add(name);
|
|
20123
|
+
}
|
|
20124
|
+
else {
|
|
20125
|
+
const [alias, argument] = name;
|
|
20126
|
+
partialScopeNames.add(alias);
|
|
20127
|
+
const variables = Array.from(extractVariables(argument));
|
|
20128
|
+
if (variables.length) {
|
|
20129
|
+
partialScope.setAlias(alias, variables[0].segments);
|
|
20130
|
+
}
|
|
20131
|
+
}
|
|
20132
|
+
}
|
|
20133
|
+
for (const child of (yield template.children(partials, sync))) {
|
|
20134
|
+
yield visit(child, partialScope);
|
|
20135
|
+
seen.add(partial.name);
|
|
20136
|
+
}
|
|
20137
|
+
partialScope.pop();
|
|
20138
|
+
}
|
|
20139
|
+
else {
|
|
20140
|
+
if (template.blockScope) {
|
|
20141
|
+
scope.push(new Set(template.blockScope()));
|
|
20142
|
+
}
|
|
20143
|
+
for (const child of (yield template.children(partials, sync))) {
|
|
20144
|
+
yield visit(child, scope);
|
|
20145
|
+
}
|
|
20146
|
+
if (template.blockScope) {
|
|
20147
|
+
scope.pop();
|
|
20148
|
+
}
|
|
20149
|
+
}
|
|
20150
|
+
}
|
|
20151
|
+
}
|
|
20152
|
+
for (const template of templates) {
|
|
20153
|
+
yield visit(template, rootScope);
|
|
20154
|
+
}
|
|
20155
|
+
return {
|
|
20156
|
+
variables: variables.asObject(),
|
|
20157
|
+
globals: globals.asObject(),
|
|
20158
|
+
locals: locals.asObject()
|
|
20159
|
+
};
|
|
20160
|
+
}
|
|
20161
|
+
/**
|
|
20162
|
+
* Statically analyze a template and report variable usage.
|
|
20163
|
+
*/
|
|
20164
|
+
function analyze(template, options = {}) {
|
|
20165
|
+
const opts = Object.assign(Object.assign({}, defaultStaticAnalysisOptions), options);
|
|
20166
|
+
return toPromise(_analyze(template, opts.partials, false));
|
|
20167
|
+
}
|
|
20168
|
+
/**
|
|
20169
|
+
* Statically analyze a template and report variable usage.
|
|
20170
|
+
*/
|
|
20171
|
+
function analyzeSync(template, options = {}) {
|
|
20172
|
+
const opts = Object.assign(Object.assign({}, defaultStaticAnalysisOptions), options);
|
|
20173
|
+
return toValueSync(_analyze(template, opts.partials, true));
|
|
20174
|
+
}
|
|
20175
|
+
/**
|
|
20176
|
+
* A stack to manage scopes while traversing templates during static analysis.
|
|
20177
|
+
*/
|
|
20178
|
+
class DummyScope {
|
|
20179
|
+
constructor(globals) {
|
|
20180
|
+
this.stack = [{ names: globals, aliases: new Map() }];
|
|
20181
|
+
}
|
|
20182
|
+
/** Return true if `name` is in scope. */
|
|
20183
|
+
has(name) {
|
|
20184
|
+
for (const scope of this.stack) {
|
|
20185
|
+
if (scope.names.has(name)) {
|
|
20186
|
+
return true;
|
|
20187
|
+
}
|
|
20188
|
+
}
|
|
20189
|
+
return false;
|
|
20190
|
+
}
|
|
20191
|
+
push(scope) {
|
|
20192
|
+
this.stack.push({ names: scope, aliases: new Map() });
|
|
20193
|
+
return this;
|
|
20194
|
+
}
|
|
20195
|
+
pop() {
|
|
20196
|
+
var _a;
|
|
20197
|
+
return (_a = this.stack.pop()) === null || _a === void 0 ? void 0 : _a.names;
|
|
20198
|
+
}
|
|
20199
|
+
// Add a name to the template scope.
|
|
20200
|
+
add(name) {
|
|
20201
|
+
this.stack[0].names.add(name);
|
|
20202
|
+
}
|
|
20203
|
+
/** Return the variable that `variable` aliases, or `variable` if it doesn't alias anything. */
|
|
20204
|
+
alias(variable) {
|
|
20205
|
+
const root = variable.segments[0];
|
|
20206
|
+
if (!isString(root))
|
|
20207
|
+
return undefined;
|
|
20208
|
+
const alias = this.getAlias(root);
|
|
20209
|
+
if (alias === undefined)
|
|
20210
|
+
return undefined;
|
|
20211
|
+
return new Variable([...alias, ...variable.segments.slice(1)], variable.location);
|
|
20212
|
+
}
|
|
20213
|
+
// TODO: `from` could be a path with multiple segments, like `include.x`.
|
|
20214
|
+
setAlias(from, to) {
|
|
20215
|
+
this.stack[this.stack.length - 1].aliases.set(from, to);
|
|
20216
|
+
}
|
|
20217
|
+
deleteAlias(name) {
|
|
20218
|
+
this.stack[this.stack.length - 1].aliases.delete(name);
|
|
20219
|
+
}
|
|
20220
|
+
getAlias(name) {
|
|
20221
|
+
for (const scope of this.stack) {
|
|
20222
|
+
if (scope.aliases.has(name)) {
|
|
20223
|
+
return scope.aliases.get(name);
|
|
20224
|
+
}
|
|
20225
|
+
// If a scope has defined `name`, then it masks aliases in parent scopes.
|
|
20226
|
+
if (scope.names.has(name)) {
|
|
20227
|
+
return undefined;
|
|
20228
|
+
}
|
|
20229
|
+
}
|
|
20230
|
+
return undefined;
|
|
20231
|
+
}
|
|
20232
|
+
}
|
|
20233
|
+
function* extractVariables(value) {
|
|
20234
|
+
if (isValueToken(value)) {
|
|
20235
|
+
yield* extractValueTokenVariables(value);
|
|
20236
|
+
}
|
|
20237
|
+
else if (value instanceof Value) {
|
|
20238
|
+
yield* extractFilteredValueVariables(value);
|
|
20239
|
+
}
|
|
20240
|
+
}
|
|
20241
|
+
function* extractFilteredValueVariables(value) {
|
|
20242
|
+
for (const token of value.initial.postfix) {
|
|
20243
|
+
if (isValueToken(token)) {
|
|
20244
|
+
yield* extractValueTokenVariables(token);
|
|
20245
|
+
}
|
|
20246
|
+
}
|
|
20247
|
+
for (const filter of value.filters) {
|
|
20248
|
+
for (const arg of filter.args) {
|
|
20249
|
+
if (isKeyValuePair(arg) && arg[1]) {
|
|
20250
|
+
yield* extractValueTokenVariables(arg[1]);
|
|
20251
|
+
}
|
|
20252
|
+
else if (isValueToken(arg)) {
|
|
20253
|
+
yield* extractValueTokenVariables(arg);
|
|
20254
|
+
}
|
|
20255
|
+
}
|
|
20256
|
+
}
|
|
20257
|
+
}
|
|
20258
|
+
function* extractValueTokenVariables(token) {
|
|
20259
|
+
if (isRangeToken(token)) {
|
|
20260
|
+
yield* extractValueTokenVariables(token.lhs);
|
|
20261
|
+
yield* extractValueTokenVariables(token.rhs);
|
|
20262
|
+
}
|
|
20263
|
+
else if (isPropertyAccessToken(token)) {
|
|
20264
|
+
yield extractPropertyAccessVariable(token);
|
|
20265
|
+
}
|
|
20266
|
+
}
|
|
20267
|
+
function extractPropertyAccessVariable(token) {
|
|
20268
|
+
const segments = [];
|
|
20269
|
+
// token is not guaranteed to have `file` set. We'll try to get it from a prop if not.
|
|
20270
|
+
let file = token.file;
|
|
20271
|
+
// Here we're flattening the first segment of a path if it is a nested path.
|
|
20272
|
+
const root = token.props[0];
|
|
20273
|
+
file = file || root.file;
|
|
20274
|
+
if (isQuotedToken(root) || isNumberToken(root) || isWordToken(root)) {
|
|
20275
|
+
segments.push(root.content);
|
|
20276
|
+
}
|
|
20277
|
+
else if (isPropertyAccessToken(root)) {
|
|
20278
|
+
// Flatten paths that start with a nested path.
|
|
20279
|
+
segments.push(...extractPropertyAccessVariable(root).segments);
|
|
20280
|
+
}
|
|
20281
|
+
for (const prop of token.props.slice(1)) {
|
|
20282
|
+
file = file || prop.file;
|
|
20283
|
+
if (isQuotedToken(prop) || isNumberToken(prop) || isWordToken(prop)) {
|
|
20284
|
+
segments.push(prop.content);
|
|
20285
|
+
}
|
|
20286
|
+
else if (isPropertyAccessToken(prop)) {
|
|
20287
|
+
segments.push(extractPropertyAccessVariable(prop));
|
|
20288
|
+
}
|
|
20289
|
+
}
|
|
20290
|
+
const [row, col] = token.getPosition();
|
|
20291
|
+
return new Variable(segments, {
|
|
20292
|
+
row,
|
|
20293
|
+
col,
|
|
20294
|
+
file
|
|
20295
|
+
});
|
|
20296
|
+
}
|
|
20297
|
+
// This is used to detect segments that can be represented with dot notation
|
|
20298
|
+
// when creating a string representation of VariableSegments.
|
|
20299
|
+
const RE_PROPERTY = /^[\u0080-\uFFFFa-zA-Z_][\u0080-\uFFFFa-zA-Z0-9_-]*$/;
|
|
20300
|
+
/**
|
|
20301
|
+
* Return a string representation of segments using dot notation where possible.
|
|
20302
|
+
* @param segments - The property names and array indices that make up a path to a variable.
|
|
20303
|
+
* @param bracketedRoot - If false (the default), don't surround the root segment with square brackets.
|
|
20304
|
+
*/
|
|
20305
|
+
function segmentsString(segments, bracketedRoot = false) {
|
|
20306
|
+
const buf = [];
|
|
20307
|
+
const root = segments[0];
|
|
20308
|
+
if (isString(root)) {
|
|
20309
|
+
if (!bracketedRoot || root.match(RE_PROPERTY)) {
|
|
20310
|
+
buf.push(`${root}`);
|
|
20311
|
+
}
|
|
20312
|
+
else {
|
|
20313
|
+
buf.push(`['${root}']`);
|
|
20314
|
+
}
|
|
20315
|
+
}
|
|
20316
|
+
for (const segment of segments.slice(1)) {
|
|
20317
|
+
if (segment instanceof Variable) {
|
|
20318
|
+
buf.push(`[${segmentsString(segment.segments)}]`);
|
|
20319
|
+
}
|
|
20320
|
+
else if (isString(segment)) {
|
|
20321
|
+
if (segment.match(RE_PROPERTY)) {
|
|
20322
|
+
buf.push(`.${segment}`);
|
|
20323
|
+
}
|
|
20324
|
+
else {
|
|
20325
|
+
buf.push(`['${segment}']`);
|
|
20326
|
+
}
|
|
20327
|
+
}
|
|
20328
|
+
else {
|
|
20329
|
+
buf.push(`[${segment}]`);
|
|
20330
|
+
}
|
|
20331
|
+
}
|
|
20332
|
+
return buf.join('');
|
|
20333
|
+
}
|
|
20334
|
+
|
|
19620
20335
|
var LookupType;
|
|
19621
20336
|
(function (LookupType) {
|
|
19622
20337
|
LookupType["Partials"] = "partials";
|
|
@@ -19633,7 +20348,7 @@ class Loader {
|
|
|
19633
20348
|
this.shouldLoadRelative = (referencedFile) => rRelativePath.test(referencedFile);
|
|
19634
20349
|
}
|
|
19635
20350
|
else {
|
|
19636
|
-
this.shouldLoadRelative = (
|
|
20351
|
+
this.shouldLoadRelative = (_referencedFile) => false;
|
|
19637
20352
|
}
|
|
19638
20353
|
this.contains = this.options.fs.contains || (() => true);
|
|
19639
20354
|
}
|
|
@@ -19690,8 +20405,11 @@ class Parser {
|
|
|
19690
20405
|
this.fs = this.liquid.options.fs;
|
|
19691
20406
|
this.parseFile = this.cache ? this._parseFileCached : this._parseFile;
|
|
19692
20407
|
this.loader = new Loader(this.liquid.options);
|
|
20408
|
+
this.parseLimit = new Limiter('parse length', liquid.options.parseLimit);
|
|
19693
20409
|
}
|
|
19694
20410
|
parse(html, filepath) {
|
|
20411
|
+
html = String(html);
|
|
20412
|
+
this.parseLimit.use(html.length);
|
|
19695
20413
|
const tokenizer = new Tokenizer(html, this.liquid.options.operators, filepath);
|
|
19696
20414
|
const tokens = tokenizer.readTopLevelTokens(this.liquid.options);
|
|
19697
20415
|
return this.parseTokens(tokens);
|
|
@@ -19699,9 +20417,20 @@ class Parser {
|
|
|
19699
20417
|
parseTokens(tokens) {
|
|
19700
20418
|
let token;
|
|
19701
20419
|
const templates = [];
|
|
20420
|
+
const errors = [];
|
|
19702
20421
|
while ((token = tokens.shift())) {
|
|
19703
|
-
|
|
20422
|
+
try {
|
|
20423
|
+
templates.push(this.parseToken(token, tokens));
|
|
20424
|
+
}
|
|
20425
|
+
catch (err) {
|
|
20426
|
+
if (this.liquid.options.catchAllErrors)
|
|
20427
|
+
errors.push(err);
|
|
20428
|
+
else
|
|
20429
|
+
throw err;
|
|
20430
|
+
}
|
|
19704
20431
|
}
|
|
20432
|
+
if (errors.length)
|
|
20433
|
+
throw new LiquidErrors(errors);
|
|
19705
20434
|
return templates;
|
|
19706
20435
|
}
|
|
19707
20436
|
parseToken(token, remainTokens) {
|
|
@@ -19709,7 +20438,7 @@ class Parser {
|
|
|
19709
20438
|
if (isTagToken(token)) {
|
|
19710
20439
|
const TagClass = this.liquid.tags[token.name];
|
|
19711
20440
|
assert(TagClass, `tag "${token.name}" not found`);
|
|
19712
|
-
return new TagClass(token, remainTokens, this.liquid);
|
|
20441
|
+
return new TagClass(token, remainTokens, this.liquid, this);
|
|
19713
20442
|
}
|
|
19714
20443
|
if (isOutputToken(token)) {
|
|
19715
20444
|
return new Output(token, this.liquid);
|
|
@@ -19717,6 +20446,8 @@ class Parser {
|
|
|
19717
20446
|
return new HTML(token);
|
|
19718
20447
|
}
|
|
19719
20448
|
catch (e) {
|
|
20449
|
+
if (LiquidError.is(e))
|
|
20450
|
+
throw e;
|
|
19720
20451
|
throw new ParseError(e, token);
|
|
19721
20452
|
}
|
|
19722
20453
|
}
|
|
@@ -19745,63 +20476,10 @@ class Parser {
|
|
|
19745
20476
|
}
|
|
19746
20477
|
*_parseFile(file, sync, type = LookupType.Root, currentFile) {
|
|
19747
20478
|
const filepath = yield this.loader.lookup(file, type, sync, currentFile);
|
|
19748
|
-
return this.
|
|
20479
|
+
return this.parse(sync ? this.fs.readFileSync(filepath) : yield this.fs.readFile(filepath), filepath);
|
|
19749
20480
|
}
|
|
19750
20481
|
}
|
|
19751
20482
|
|
|
19752
|
-
const rHex = /[\da-fA-F]/;
|
|
19753
|
-
const rOct = /[0-7]/;
|
|
19754
|
-
const escapeChar = {
|
|
19755
|
-
b: '\b',
|
|
19756
|
-
f: '\f',
|
|
19757
|
-
n: '\n',
|
|
19758
|
-
r: '\r',
|
|
19759
|
-
t: '\t',
|
|
19760
|
-
v: '\x0B'
|
|
19761
|
-
};
|
|
19762
|
-
function hexVal(c) {
|
|
19763
|
-
const code = c.charCodeAt(0);
|
|
19764
|
-
if (code >= 97)
|
|
19765
|
-
return code - 87;
|
|
19766
|
-
if (code >= 65)
|
|
19767
|
-
return code - 55;
|
|
19768
|
-
return code - 48;
|
|
19769
|
-
}
|
|
19770
|
-
function parseStringLiteral(str) {
|
|
19771
|
-
let ret = '';
|
|
19772
|
-
for (let i = 1; i < str.length - 1; i++) {
|
|
19773
|
-
if (str[i] !== '\\') {
|
|
19774
|
-
ret += str[i];
|
|
19775
|
-
continue;
|
|
19776
|
-
}
|
|
19777
|
-
if (escapeChar[str[i + 1]] !== undefined) {
|
|
19778
|
-
ret += escapeChar[str[++i]];
|
|
19779
|
-
}
|
|
19780
|
-
else if (str[i + 1] === 'u') {
|
|
19781
|
-
let val = 0;
|
|
19782
|
-
let j = i + 2;
|
|
19783
|
-
while (j <= i + 5 && rHex.test(str[j])) {
|
|
19784
|
-
val = val * 16 + hexVal(str[j++]);
|
|
19785
|
-
}
|
|
19786
|
-
i = j - 1;
|
|
19787
|
-
ret += String.fromCharCode(val);
|
|
19788
|
-
}
|
|
19789
|
-
else if (!rOct.test(str[i + 1])) {
|
|
19790
|
-
ret += str[++i];
|
|
19791
|
-
}
|
|
19792
|
-
else {
|
|
19793
|
-
let j = i + 1;
|
|
19794
|
-
let val = 0;
|
|
19795
|
-
while (j <= i + 3 && rOct.test(str[j])) {
|
|
19796
|
-
val = val * 8 + hexVal(str[j++]);
|
|
19797
|
-
}
|
|
19798
|
-
i = j - 1;
|
|
19799
|
-
ret += String.fromCharCode(val);
|
|
19800
|
-
}
|
|
19801
|
-
}
|
|
19802
|
-
return ret;
|
|
19803
|
-
}
|
|
19804
|
-
|
|
19805
20483
|
var TokenKind;
|
|
19806
20484
|
(function (TokenKind) {
|
|
19807
20485
|
TokenKind[TokenKind["Number"] = 1] = "Number";
|
|
@@ -19816,6 +20494,7 @@ var TokenKind;
|
|
|
19816
20494
|
TokenKind[TokenKind["Range"] = 512] = "Range";
|
|
19817
20495
|
TokenKind[TokenKind["Quoted"] = 1024] = "Quoted";
|
|
19818
20496
|
TokenKind[TokenKind["Operator"] = 2048] = "Operator";
|
|
20497
|
+
TokenKind[TokenKind["FilteredValue"] = 4096] = "FilteredValue";
|
|
19819
20498
|
TokenKind[TokenKind["Delimited"] = 12] = "Delimited";
|
|
19820
20499
|
})(TokenKind || (TokenKind = {}));
|
|
19821
20500
|
|
|
@@ -19837,9 +20516,6 @@ function isTagToken(val) {
|
|
|
19837
20516
|
function isQuotedToken(val) {
|
|
19838
20517
|
return getKind(val) === TokenKind.Quoted;
|
|
19839
20518
|
}
|
|
19840
|
-
function isLiteralToken(val) {
|
|
19841
|
-
return getKind(val) === TokenKind.Literal;
|
|
19842
|
-
}
|
|
19843
20519
|
function isNumberToken(val) {
|
|
19844
20520
|
return getKind(val) === TokenKind.Number;
|
|
19845
20521
|
}
|
|
@@ -19852,25 +20528,33 @@ function isWordToken(val) {
|
|
|
19852
20528
|
function isRangeToken(val) {
|
|
19853
20529
|
return getKind(val) === TokenKind.Range;
|
|
19854
20530
|
}
|
|
20531
|
+
function isValueToken(val) {
|
|
20532
|
+
// valueTokenBitMask = TokenKind.Number | TokenKind.Literal | TokenKind.Quoted | TokenKind.PropertyAccess | TokenKind.Range
|
|
20533
|
+
return (getKind(val) & 1667) > 0;
|
|
20534
|
+
}
|
|
19855
20535
|
function getKind(val) {
|
|
19856
20536
|
return val ? val.kind : -1;
|
|
19857
20537
|
}
|
|
19858
20538
|
|
|
19859
20539
|
class Context {
|
|
19860
|
-
constructor(env = {}, opts = defaultOptions, renderOptions = {}) {
|
|
19861
|
-
var _a, _b, _c;
|
|
20540
|
+
constructor(env = {}, opts = defaultOptions, renderOptions = {}, { memoryLimit, renderLimit } = {}) {
|
|
20541
|
+
var _a, _b, _c, _d, _e;
|
|
19862
20542
|
/**
|
|
19863
20543
|
* insert a Context-level empty scope,
|
|
19864
20544
|
* for tags like `{% capture %}` `{% assign %}` to operate
|
|
19865
20545
|
*/
|
|
19866
20546
|
this.scopes = [{}];
|
|
19867
20547
|
this.registers = {};
|
|
20548
|
+
this.breakCalled = false;
|
|
20549
|
+
this.continueCalled = false;
|
|
19868
20550
|
this.sync = !!renderOptions.sync;
|
|
19869
20551
|
this.opts = opts;
|
|
19870
20552
|
this.globals = (_a = renderOptions.globals) !== null && _a !== void 0 ? _a : opts.globals;
|
|
19871
|
-
this.environments = env;
|
|
20553
|
+
this.environments = isObject(env) ? env : Object(env);
|
|
19872
20554
|
this.strictVariables = (_b = renderOptions.strictVariables) !== null && _b !== void 0 ? _b : this.opts.strictVariables;
|
|
19873
20555
|
this.ownPropertyOnly = (_c = renderOptions.ownPropertyOnly) !== null && _c !== void 0 ? _c : opts.ownPropertyOnly;
|
|
20556
|
+
this.memoryLimit = memoryLimit !== null && memoryLimit !== void 0 ? memoryLimit : new Limiter('memory alloc', (_d = renderOptions.memoryLimit) !== null && _d !== void 0 ? _d : opts.memoryLimit);
|
|
20557
|
+
this.renderLimit = renderLimit !== null && renderLimit !== void 0 ? renderLimit : new Limiter('template render', getPerformance().now() + ((_e = renderOptions.renderLimit) !== null && _e !== void 0 ? _e : opts.renderLimit));
|
|
19874
20558
|
}
|
|
19875
20559
|
getRegister(key) {
|
|
19876
20560
|
return (this.registers[key] = this.registers[key] || {});
|
|
@@ -19898,7 +20582,7 @@ class Context {
|
|
|
19898
20582
|
return toValueSync(this._get(paths));
|
|
19899
20583
|
}
|
|
19900
20584
|
*_get(paths) {
|
|
19901
|
-
const scope = this.findScope(paths[0]);
|
|
20585
|
+
const scope = this.findScope(paths[0]); // first prop should always be a string
|
|
19902
20586
|
return yield this._getFromScope(scope, paths);
|
|
19903
20587
|
}
|
|
19904
20588
|
/**
|
|
@@ -19907,12 +20591,12 @@ class Context {
|
|
|
19907
20591
|
getFromScope(scope, paths) {
|
|
19908
20592
|
return toValueSync(this._getFromScope(scope, paths));
|
|
19909
20593
|
}
|
|
19910
|
-
*_getFromScope(scope, paths) {
|
|
20594
|
+
*_getFromScope(scope, paths, strictVariables = this.strictVariables) {
|
|
19911
20595
|
if (isString(paths))
|
|
19912
20596
|
paths = paths.split('.');
|
|
19913
20597
|
for (let i = 0; i < paths.length; i++) {
|
|
19914
20598
|
scope = yield readProperty(scope, paths[i], this.ownPropertyOnly);
|
|
19915
|
-
if (
|
|
20599
|
+
if (strictVariables && isUndefined(scope)) {
|
|
19916
20600
|
throw new InternalUndefinedVariableError(paths.slice(0, i + 1).join('.'));
|
|
19917
20601
|
}
|
|
19918
20602
|
}
|
|
@@ -19927,6 +20611,16 @@ class Context {
|
|
|
19927
20611
|
bottom() {
|
|
19928
20612
|
return this.scopes[0];
|
|
19929
20613
|
}
|
|
20614
|
+
spawn(scope = {}) {
|
|
20615
|
+
return new Context(scope, this.opts, {
|
|
20616
|
+
sync: this.sync,
|
|
20617
|
+
globals: this.globals,
|
|
20618
|
+
strictVariables: this.strictVariables
|
|
20619
|
+
}, {
|
|
20620
|
+
renderLimit: this.renderLimit,
|
|
20621
|
+
memoryLimit: this.memoryLimit
|
|
20622
|
+
});
|
|
20623
|
+
}
|
|
19930
20624
|
findScope(key) {
|
|
19931
20625
|
for (let i = this.scopes.length - 1; i >= 0; i--) {
|
|
19932
20626
|
const candidate = this.scopes[i];
|
|
@@ -19940,6 +20634,7 @@ class Context {
|
|
|
19940
20634
|
}
|
|
19941
20635
|
function readProperty(obj, key, ownPropertyOnly) {
|
|
19942
20636
|
obj = toLiquid(obj);
|
|
20637
|
+
key = toValue(key);
|
|
19943
20638
|
if (isNil(obj))
|
|
19944
20639
|
return obj;
|
|
19945
20640
|
if (isArray(obj) && key < 0)
|
|
@@ -19958,7 +20653,7 @@ function readProperty(obj, key, ownPropertyOnly) {
|
|
|
19958
20653
|
return value;
|
|
19959
20654
|
}
|
|
19960
20655
|
function readJSProperty(obj, key, ownPropertyOnly) {
|
|
19961
|
-
if (ownPropertyOnly && !
|
|
20656
|
+
if (ownPropertyOnly && !hasOwnProperty.call(obj, key) && !(obj instanceof Drop))
|
|
19962
20657
|
return undefined;
|
|
19963
20658
|
return obj[key];
|
|
19964
20659
|
}
|
|
@@ -19973,7 +20668,7 @@ function readLast(obj) {
|
|
|
19973
20668
|
return obj['last'];
|
|
19974
20669
|
}
|
|
19975
20670
|
function readSize(obj) {
|
|
19976
|
-
if (
|
|
20671
|
+
if (hasOwnProperty.call(obj, 'size') || obj['size'] !== undefined)
|
|
19977
20672
|
return obj['size'];
|
|
19978
20673
|
if (isArray(obj) || isString(obj))
|
|
19979
20674
|
return obj.length;
|
|
@@ -20025,25 +20720,83 @@ var mathFilters = /*#__PURE__*/Object.freeze({
|
|
|
20025
20720
|
plus: plus
|
|
20026
20721
|
});
|
|
20027
20722
|
|
|
20028
|
-
const url_decode = (x) => stringify(x)
|
|
20029
|
-
const url_encode = (x) => stringify(x).
|
|
20723
|
+
const url_decode = (x) => decodeURIComponent(stringify(x)).replace(/\+/g, ' ');
|
|
20724
|
+
const url_encode = (x) => encodeURIComponent(stringify(x)).replace(/%20/g, '+');
|
|
20725
|
+
const cgi_escape = (x) => encodeURIComponent(stringify(x))
|
|
20726
|
+
.replace(/%20/g, '+')
|
|
20727
|
+
.replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16).toUpperCase());
|
|
20728
|
+
const uri_escape = (x) => encodeURI(stringify(x))
|
|
20729
|
+
.replace(/%5B/g, '[')
|
|
20730
|
+
.replace(/%5D/g, ']');
|
|
20731
|
+
const rSlugifyDefault = /[^\p{M}\p{L}\p{Nd}]+/ug;
|
|
20732
|
+
const rSlugifyReplacers = {
|
|
20733
|
+
'raw': /\s+/g,
|
|
20734
|
+
'default': rSlugifyDefault,
|
|
20735
|
+
'pretty': /[^\p{M}\p{L}\p{Nd}._~!$&'()+,;=@]+/ug,
|
|
20736
|
+
'ascii': /[^A-Za-z0-9]+/g,
|
|
20737
|
+
'latin': rSlugifyDefault,
|
|
20738
|
+
'none': null
|
|
20739
|
+
};
|
|
20740
|
+
function slugify(str, mode = 'default', cased = false) {
|
|
20741
|
+
str = stringify(str);
|
|
20742
|
+
const replacer = rSlugifyReplacers[mode];
|
|
20743
|
+
if (replacer) {
|
|
20744
|
+
if (mode === 'latin')
|
|
20745
|
+
str = removeAccents(str);
|
|
20746
|
+
str = str.replace(replacer, '-').replace(/^-|-$/g, '');
|
|
20747
|
+
}
|
|
20748
|
+
return cased ? str : str.toLowerCase();
|
|
20749
|
+
}
|
|
20750
|
+
function removeAccents(str) {
|
|
20751
|
+
return str.replace(/[àáâãäå]/g, 'a')
|
|
20752
|
+
.replace(/[æ]/g, 'ae')
|
|
20753
|
+
.replace(/[ç]/g, 'c')
|
|
20754
|
+
.replace(/[èéêë]/g, 'e')
|
|
20755
|
+
.replace(/[ìíîï]/g, 'i')
|
|
20756
|
+
.replace(/[ð]/g, 'd')
|
|
20757
|
+
.replace(/[ñ]/g, 'n')
|
|
20758
|
+
.replace(/[òóôõöø]/g, 'o')
|
|
20759
|
+
.replace(/[ùúûü]/g, 'u')
|
|
20760
|
+
.replace(/[ýÿ]/g, 'y')
|
|
20761
|
+
.replace(/[ß]/g, 'ss')
|
|
20762
|
+
.replace(/[œ]/g, 'oe')
|
|
20763
|
+
.replace(/[þ]/g, 'th')
|
|
20764
|
+
.replace(/[ẞ]/g, 'SS')
|
|
20765
|
+
.replace(/[Œ]/g, 'OE')
|
|
20766
|
+
.replace(/[Þ]/g, 'TH');
|
|
20767
|
+
}
|
|
20030
20768
|
|
|
20031
20769
|
var urlFilters = /*#__PURE__*/Object.freeze({
|
|
20032
20770
|
__proto__: null,
|
|
20033
20771
|
url_decode: url_decode,
|
|
20034
|
-
url_encode: url_encode
|
|
20772
|
+
url_encode: url_encode,
|
|
20773
|
+
cgi_escape: cgi_escape,
|
|
20774
|
+
uri_escape: uri_escape,
|
|
20775
|
+
slugify: slugify
|
|
20035
20776
|
});
|
|
20036
20777
|
|
|
20037
|
-
const join = argumentsToValue((v, arg)
|
|
20038
|
-
const
|
|
20039
|
-
const
|
|
20040
|
-
const
|
|
20778
|
+
const join = argumentsToValue(function (v, arg) {
|
|
20779
|
+
const array = toArray(v);
|
|
20780
|
+
const sep = isNil(arg) ? ' ' : stringify(arg);
|
|
20781
|
+
const complexity = array.length * (1 + sep.length);
|
|
20782
|
+
this.context.memoryLimit.use(complexity);
|
|
20783
|
+
return array.join(sep);
|
|
20784
|
+
});
|
|
20785
|
+
const last$1 = argumentsToValue((v) => isArrayLike(v) ? last(v) : '');
|
|
20786
|
+
const first = argumentsToValue((v) => isArrayLike(v) ? v[0] : '');
|
|
20787
|
+
const reverse = argumentsToValue(function (v) {
|
|
20788
|
+
const array = toArray(v);
|
|
20789
|
+
this.context.memoryLimit.use(array.length);
|
|
20790
|
+
return [...array].reverse();
|
|
20791
|
+
});
|
|
20041
20792
|
function* sort(arr, property) {
|
|
20042
20793
|
const values = [];
|
|
20043
|
-
|
|
20794
|
+
const array = toArray(arr);
|
|
20795
|
+
this.context.memoryLimit.use(array.length);
|
|
20796
|
+
for (const item of array) {
|
|
20044
20797
|
values.push([
|
|
20045
20798
|
item,
|
|
20046
|
-
property ? yield this.context._getFromScope(item, stringify(property).split('.')) : item
|
|
20799
|
+
property ? yield this.context._getFromScope(item, stringify(property).split('.'), false) : item
|
|
20047
20800
|
]);
|
|
20048
20801
|
}
|
|
20049
20802
|
return values.sort((lhs, rhs) => {
|
|
@@ -20053,29 +20806,65 @@ function* sort(arr, property) {
|
|
|
20053
20806
|
}).map(tuple => tuple[0]);
|
|
20054
20807
|
}
|
|
20055
20808
|
function sort_natural(input, property) {
|
|
20056
|
-
input = toValue(input);
|
|
20057
20809
|
const propertyString = stringify(property);
|
|
20058
20810
|
const compare = property === undefined
|
|
20059
20811
|
? caseInsensitiveCompare
|
|
20060
20812
|
: (lhs, rhs) => caseInsensitiveCompare(lhs[propertyString], rhs[propertyString]);
|
|
20061
|
-
|
|
20813
|
+
const array = toArray(input);
|
|
20814
|
+
this.context.memoryLimit.use(array.length);
|
|
20815
|
+
return [...array].sort(compare);
|
|
20062
20816
|
}
|
|
20063
20817
|
const size = (v) => (v && v.length) || 0;
|
|
20064
20818
|
function* map(arr, property) {
|
|
20065
20819
|
const results = [];
|
|
20066
|
-
|
|
20067
|
-
|
|
20820
|
+
const array = toArray(arr);
|
|
20821
|
+
this.context.memoryLimit.use(array.length);
|
|
20822
|
+
for (const item of array) {
|
|
20823
|
+
results.push(yield this.context._getFromScope(item, stringify(property), false));
|
|
20068
20824
|
}
|
|
20069
20825
|
return results;
|
|
20070
20826
|
}
|
|
20827
|
+
function* sum(arr, property) {
|
|
20828
|
+
let sum = 0;
|
|
20829
|
+
const array = toArray(arr);
|
|
20830
|
+
for (const item of array) {
|
|
20831
|
+
const data = Number(property ? yield this.context._getFromScope(item, stringify(property), false) : item);
|
|
20832
|
+
sum += Number.isNaN(data) ? 0 : data;
|
|
20833
|
+
}
|
|
20834
|
+
return sum;
|
|
20835
|
+
}
|
|
20071
20836
|
function compact(arr) {
|
|
20072
|
-
|
|
20073
|
-
|
|
20837
|
+
const array = toArray(arr);
|
|
20838
|
+
this.context.memoryLimit.use(array.length);
|
|
20839
|
+
return array.filter(x => !isNil(toValue(x)));
|
|
20074
20840
|
}
|
|
20075
20841
|
function concat(v, arg = []) {
|
|
20076
|
-
|
|
20077
|
-
|
|
20078
|
-
|
|
20842
|
+
const lhs = toArray(v);
|
|
20843
|
+
const rhs = toArray(arg);
|
|
20844
|
+
this.context.memoryLimit.use(lhs.length + rhs.length);
|
|
20845
|
+
return lhs.concat(rhs);
|
|
20846
|
+
}
|
|
20847
|
+
function push(v, arg) {
|
|
20848
|
+
return concat.call(this, v, [arg]);
|
|
20849
|
+
}
|
|
20850
|
+
function unshift(v, arg) {
|
|
20851
|
+
const array = toArray(v);
|
|
20852
|
+
this.context.memoryLimit.use(array.length);
|
|
20853
|
+
const clone = [...array];
|
|
20854
|
+
clone.unshift(arg);
|
|
20855
|
+
return clone;
|
|
20856
|
+
}
|
|
20857
|
+
function pop(v) {
|
|
20858
|
+
const clone = [...toArray(v)];
|
|
20859
|
+
clone.pop();
|
|
20860
|
+
return clone;
|
|
20861
|
+
}
|
|
20862
|
+
function shift(v) {
|
|
20863
|
+
const array = toArray(v);
|
|
20864
|
+
this.context.memoryLimit.use(array.length);
|
|
20865
|
+
const clone = [...array];
|
|
20866
|
+
clone.shift();
|
|
20867
|
+
return clone;
|
|
20079
20868
|
}
|
|
20080
20869
|
function slice(v, begin, length = 1) {
|
|
20081
20870
|
v = toValue(v);
|
|
@@ -20084,31 +20873,98 @@ function slice(v, begin, length = 1) {
|
|
|
20084
20873
|
if (!isArray(v))
|
|
20085
20874
|
v = stringify(v);
|
|
20086
20875
|
begin = begin < 0 ? v.length + begin : begin;
|
|
20876
|
+
this.context.memoryLimit.use(length);
|
|
20087
20877
|
return v.slice(begin, begin + length);
|
|
20088
20878
|
}
|
|
20089
20879
|
function* where(arr, property, expected) {
|
|
20090
20880
|
const values = [];
|
|
20091
|
-
arr = toArray(
|
|
20881
|
+
arr = toArray(arr);
|
|
20882
|
+
this.context.memoryLimit.use(arr.length);
|
|
20883
|
+
const token = new Tokenizer(stringify(property)).readScopeValue();
|
|
20092
20884
|
for (const item of arr) {
|
|
20093
|
-
values.push(yield this.context.
|
|
20885
|
+
values.push(yield evalToken(token, this.context.spawn(item)));
|
|
20094
20886
|
}
|
|
20887
|
+
const matcher = this.context.opts.jekyllWhere
|
|
20888
|
+
? (v) => EmptyDrop.is(expected) ? equals(v, expected) : (isArray(v) ? arrayIncludes(v, expected) : equals(v, expected))
|
|
20889
|
+
: (v) => equals(v, expected);
|
|
20095
20890
|
return arr.filter((_, i) => {
|
|
20096
20891
|
if (expected === undefined)
|
|
20097
20892
|
return isTruthy(values[i], this.context);
|
|
20098
|
-
|
|
20099
|
-
return expected.equals(values[i]);
|
|
20100
|
-
return values[i] === expected;
|
|
20893
|
+
return matcher(values[i]);
|
|
20101
20894
|
});
|
|
20102
20895
|
}
|
|
20896
|
+
function* where_exp(arr, itemName, exp) {
|
|
20897
|
+
const filtered = [];
|
|
20898
|
+
const keyTemplate = new Value(stringify(exp), this.liquid);
|
|
20899
|
+
const array = toArray(arr);
|
|
20900
|
+
this.context.memoryLimit.use(array.length);
|
|
20901
|
+
for (const item of array) {
|
|
20902
|
+
const value = yield keyTemplate.value(this.context.spawn({ [itemName]: item }));
|
|
20903
|
+
if (value)
|
|
20904
|
+
filtered.push(item);
|
|
20905
|
+
}
|
|
20906
|
+
return filtered;
|
|
20907
|
+
}
|
|
20908
|
+
function* group_by(arr, property) {
|
|
20909
|
+
const map = new Map();
|
|
20910
|
+
arr = toEnumerable(arr);
|
|
20911
|
+
const token = new Tokenizer(stringify(property)).readScopeValue();
|
|
20912
|
+
this.context.memoryLimit.use(arr.length);
|
|
20913
|
+
for (const item of arr) {
|
|
20914
|
+
const key = yield evalToken(token, this.context.spawn(item));
|
|
20915
|
+
if (!map.has(key))
|
|
20916
|
+
map.set(key, []);
|
|
20917
|
+
map.get(key).push(item);
|
|
20918
|
+
}
|
|
20919
|
+
return [...map.entries()].map(([name, items]) => ({ name, items }));
|
|
20920
|
+
}
|
|
20921
|
+
function* group_by_exp(arr, itemName, exp) {
|
|
20922
|
+
const map = new Map();
|
|
20923
|
+
const keyTemplate = new Value(stringify(exp), this.liquid);
|
|
20924
|
+
arr = toEnumerable(arr);
|
|
20925
|
+
this.context.memoryLimit.use(arr.length);
|
|
20926
|
+
for (const item of arr) {
|
|
20927
|
+
const key = yield keyTemplate.value(this.context.spawn({ [itemName]: item }));
|
|
20928
|
+
if (!map.has(key))
|
|
20929
|
+
map.set(key, []);
|
|
20930
|
+
map.get(key).push(item);
|
|
20931
|
+
}
|
|
20932
|
+
return [...map.entries()].map(([name, items]) => ({ name, items }));
|
|
20933
|
+
}
|
|
20934
|
+
function* find(arr, property, expected) {
|
|
20935
|
+
const token = new Tokenizer(stringify(property)).readScopeValue();
|
|
20936
|
+
const array = toArray(arr);
|
|
20937
|
+
for (const item of array) {
|
|
20938
|
+
const value = yield evalToken(token, this.context.spawn(item));
|
|
20939
|
+
if (equals(value, expected))
|
|
20940
|
+
return item;
|
|
20941
|
+
}
|
|
20942
|
+
}
|
|
20943
|
+
function* find_exp(arr, itemName, exp) {
|
|
20944
|
+
const predicate = new Value(stringify(exp), this.liquid);
|
|
20945
|
+
const array = toArray(arr);
|
|
20946
|
+
for (const item of array) {
|
|
20947
|
+
const value = yield predicate.value(this.context.spawn({ [itemName]: item }));
|
|
20948
|
+
if (value)
|
|
20949
|
+
return item;
|
|
20950
|
+
}
|
|
20951
|
+
}
|
|
20103
20952
|
function uniq(arr) {
|
|
20104
|
-
arr =
|
|
20105
|
-
|
|
20106
|
-
return (arr
|
|
20107
|
-
|
|
20108
|
-
|
|
20109
|
-
|
|
20110
|
-
|
|
20111
|
-
|
|
20953
|
+
arr = toArray(arr);
|
|
20954
|
+
this.context.memoryLimit.use(arr.length);
|
|
20955
|
+
return [...new Set(arr)];
|
|
20956
|
+
}
|
|
20957
|
+
function sample(v, count = 1) {
|
|
20958
|
+
v = toValue(v);
|
|
20959
|
+
if (isNil(v))
|
|
20960
|
+
return [];
|
|
20961
|
+
if (!isArray(v))
|
|
20962
|
+
v = stringify(v);
|
|
20963
|
+
this.context.memoryLimit.use(count);
|
|
20964
|
+
const shuffled = [...v].sort(() => Math.random() - 0.5);
|
|
20965
|
+
if (count === 1)
|
|
20966
|
+
return shuffled[0];
|
|
20967
|
+
return shuffled.slice(0, count);
|
|
20112
20968
|
}
|
|
20113
20969
|
|
|
20114
20970
|
var arrayFilters = /*#__PURE__*/Object.freeze({
|
|
@@ -20121,69 +20977,94 @@ var arrayFilters = /*#__PURE__*/Object.freeze({
|
|
|
20121
20977
|
sort_natural: sort_natural,
|
|
20122
20978
|
size: size,
|
|
20123
20979
|
map: map,
|
|
20980
|
+
sum: sum,
|
|
20124
20981
|
compact: compact,
|
|
20125
20982
|
concat: concat,
|
|
20983
|
+
push: push,
|
|
20984
|
+
unshift: unshift,
|
|
20985
|
+
pop: pop,
|
|
20986
|
+
shift: shift,
|
|
20126
20987
|
slice: slice,
|
|
20127
20988
|
where: where,
|
|
20128
|
-
|
|
20989
|
+
where_exp: where_exp,
|
|
20990
|
+
group_by: group_by,
|
|
20991
|
+
group_by_exp: group_by_exp,
|
|
20992
|
+
find: find,
|
|
20993
|
+
find_exp: find_exp,
|
|
20994
|
+
uniq: uniq,
|
|
20995
|
+
sample: sample
|
|
20129
20996
|
});
|
|
20130
20997
|
|
|
20131
20998
|
function date(v, format, timezoneOffset) {
|
|
20132
|
-
|
|
20999
|
+
var _a, _b, _c;
|
|
21000
|
+
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);
|
|
21001
|
+
this.context.memoryLimit.use(size);
|
|
21002
|
+
const date = parseDate(v, this.context.opts, timezoneOffset);
|
|
21003
|
+
if (!date)
|
|
21004
|
+
return v;
|
|
21005
|
+
format = toValue(format);
|
|
21006
|
+
format = isNil(format) ? this.context.opts.dateFormat : stringify(format);
|
|
21007
|
+
return strftime(date, format);
|
|
21008
|
+
}
|
|
21009
|
+
function date_to_xmlschema(v) {
|
|
21010
|
+
return date.call(this, v, '%Y-%m-%dT%H:%M:%S%:z');
|
|
21011
|
+
}
|
|
21012
|
+
function date_to_rfc822(v) {
|
|
21013
|
+
return date.call(this, v, '%a, %d %b %Y %H:%M:%S %z');
|
|
21014
|
+
}
|
|
21015
|
+
function date_to_string(v, type, style) {
|
|
21016
|
+
return stringify_date.call(this, v, '%b', type, style);
|
|
21017
|
+
}
|
|
21018
|
+
function date_to_long_string(v, type, style) {
|
|
21019
|
+
return stringify_date.call(this, v, '%B', type, style);
|
|
21020
|
+
}
|
|
21021
|
+
function stringify_date(v, month_type, type, style) {
|
|
21022
|
+
const date = parseDate(v, this.context.opts);
|
|
21023
|
+
if (!date)
|
|
21024
|
+
return v;
|
|
21025
|
+
if (type === 'ordinal') {
|
|
21026
|
+
const d = date.getDate();
|
|
21027
|
+
return style === 'US'
|
|
21028
|
+
? strftime(date, `${month_type} ${d}%q, %Y`)
|
|
21029
|
+
: strftime(date, `${d}%q ${month_type} %Y`);
|
|
21030
|
+
}
|
|
21031
|
+
return strftime(date, `%d ${month_type} %Y`);
|
|
21032
|
+
}
|
|
21033
|
+
function parseDate(v, opts, timezoneOffset) {
|
|
20133
21034
|
let date;
|
|
21035
|
+
const defaultTimezoneOffset = timezoneOffset !== null && timezoneOffset !== void 0 ? timezoneOffset : opts.timezoneOffset;
|
|
21036
|
+
const locale = opts.locale;
|
|
20134
21037
|
v = toValue(v);
|
|
20135
|
-
format = toValue(format);
|
|
20136
|
-
if (isNil(format))
|
|
20137
|
-
format = opts.dateFormat;
|
|
20138
|
-
else
|
|
20139
|
-
format = stringify(format);
|
|
20140
21038
|
if (v === 'now' || v === 'today') {
|
|
20141
|
-
date = new Date();
|
|
21039
|
+
date = new LiquidDate(Date.now(), locale, defaultTimezoneOffset);
|
|
20142
21040
|
}
|
|
20143
21041
|
else if (isNumber(v)) {
|
|
20144
|
-
date = new
|
|
21042
|
+
date = new LiquidDate(v * 1000, locale, defaultTimezoneOffset);
|
|
20145
21043
|
}
|
|
20146
21044
|
else if (isString(v)) {
|
|
20147
21045
|
if (/^\d+$/.test(v)) {
|
|
20148
|
-
date = new
|
|
21046
|
+
date = new LiquidDate(+v * 1000, locale, defaultTimezoneOffset);
|
|
20149
21047
|
}
|
|
20150
|
-
else if (opts.preserveTimezones) {
|
|
20151
|
-
date =
|
|
21048
|
+
else if (opts.preserveTimezones && timezoneOffset === undefined) {
|
|
21049
|
+
date = LiquidDate.createDateFixedToTimezone(v, locale);
|
|
20152
21050
|
}
|
|
20153
21051
|
else {
|
|
20154
|
-
date = new
|
|
21052
|
+
date = new LiquidDate(v, locale, defaultTimezoneOffset);
|
|
20155
21053
|
}
|
|
20156
21054
|
}
|
|
20157
21055
|
else {
|
|
20158
|
-
date = v;
|
|
20159
|
-
}
|
|
20160
|
-
if (!isValidDate(date))
|
|
20161
|
-
return v;
|
|
20162
|
-
if (timezoneOffset !== undefined) {
|
|
20163
|
-
date = new TimezoneDate(date, parseTimezoneOffset(date, timezoneOffset));
|
|
21056
|
+
date = new LiquidDate(v, locale, defaultTimezoneOffset);
|
|
20164
21057
|
}
|
|
20165
|
-
|
|
20166
|
-
date = new TimezoneDate(date, parseTimezoneOffset(date, opts.timezoneOffset));
|
|
20167
|
-
}
|
|
20168
|
-
return strftime(date, format);
|
|
20169
|
-
}
|
|
20170
|
-
function isValidDate(date) {
|
|
20171
|
-
return (date instanceof Date || date instanceof TimezoneDate) && !isNaN(date.getTime());
|
|
20172
|
-
}
|
|
20173
|
-
/**
|
|
20174
|
-
* need pass in a `date` because offset is dependent on whether DST is active
|
|
20175
|
-
*/
|
|
20176
|
-
function parseTimezoneOffset(date, timeZone) {
|
|
20177
|
-
if (isNumber(timeZone))
|
|
20178
|
-
return timeZone;
|
|
20179
|
-
const utcDate = new Date(date.toLocaleString('en-US', { timeZone: 'UTC' }));
|
|
20180
|
-
const tzDate = new Date(date.toLocaleString('en-US', { timeZone }));
|
|
20181
|
-
return (utcDate.getTime() - tzDate.getTime()) / 6e4;
|
|
21058
|
+
return date.valid() ? date : undefined;
|
|
20182
21059
|
}
|
|
20183
21060
|
|
|
20184
21061
|
var dateFilters = /*#__PURE__*/Object.freeze({
|
|
20185
21062
|
__proto__: null,
|
|
20186
|
-
date: date
|
|
21063
|
+
date: date,
|
|
21064
|
+
date_to_xmlschema: date_to_xmlschema,
|
|
21065
|
+
date_to_rfc822: date_to_rfc822,
|
|
21066
|
+
date_to_string: date_to_string,
|
|
21067
|
+
date_to_long_string: date_to_long_string
|
|
20187
21068
|
});
|
|
20188
21069
|
|
|
20189
21070
|
/**
|
|
@@ -20191,50 +21072,74 @@ var dateFilters = /*#__PURE__*/Object.freeze({
|
|
|
20191
21072
|
*
|
|
20192
21073
|
* * prefer stringify() to String() since `undefined`, `null` should eval ''
|
|
20193
21074
|
*/
|
|
21075
|
+
const rCJKWord = /[\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF]/gu;
|
|
21076
|
+
// Word boundary followed by word characters (for detecting words)
|
|
21077
|
+
const rNonCJKWord = /[^\u4E00-\u9FFF\uF900-\uFAFF\u3400-\u4DBF\u3040-\u309F\u30A0-\u30FF\uAC00-\uD7AF\s]+/gu;
|
|
20194
21078
|
function append(v, arg) {
|
|
20195
21079
|
assert(arguments.length === 2, 'append expect 2 arguments');
|
|
20196
|
-
|
|
21080
|
+
const lhs = stringify(v);
|
|
21081
|
+
const rhs = stringify(arg);
|
|
21082
|
+
this.context.memoryLimit.use(lhs.length + rhs.length);
|
|
21083
|
+
return lhs + rhs;
|
|
20197
21084
|
}
|
|
20198
21085
|
function prepend(v, arg) {
|
|
20199
21086
|
assert(arguments.length === 2, 'prepend expect 2 arguments');
|
|
20200
|
-
|
|
21087
|
+
const lhs = stringify(v);
|
|
21088
|
+
const rhs = stringify(arg);
|
|
21089
|
+
this.context.memoryLimit.use(lhs.length + rhs.length);
|
|
21090
|
+
return rhs + lhs;
|
|
20201
21091
|
}
|
|
20202
21092
|
function lstrip(v, chars) {
|
|
21093
|
+
const str = stringify(v);
|
|
21094
|
+
this.context.memoryLimit.use(str.length);
|
|
20203
21095
|
if (chars) {
|
|
20204
21096
|
chars = escapeRegExp(stringify(chars));
|
|
20205
|
-
return
|
|
21097
|
+
return str.replace(new RegExp(`^[${chars}]+`, 'g'), '');
|
|
20206
21098
|
}
|
|
20207
|
-
return
|
|
21099
|
+
return str.replace(/^\s+/, '');
|
|
20208
21100
|
}
|
|
20209
21101
|
function downcase(v) {
|
|
20210
|
-
|
|
21102
|
+
const str = stringify(v);
|
|
21103
|
+
this.context.memoryLimit.use(str.length);
|
|
21104
|
+
return str.toLowerCase();
|
|
20211
21105
|
}
|
|
20212
|
-
function upcase(
|
|
21106
|
+
function upcase(v) {
|
|
21107
|
+
const str = stringify(v);
|
|
21108
|
+
this.context.memoryLimit.use(str.length);
|
|
20213
21109
|
return stringify(str).toUpperCase();
|
|
20214
21110
|
}
|
|
20215
21111
|
function remove(v, arg) {
|
|
20216
|
-
|
|
21112
|
+
const str = stringify(v);
|
|
21113
|
+
this.context.memoryLimit.use(str.length);
|
|
21114
|
+
return str.split(stringify(arg)).join('');
|
|
20217
21115
|
}
|
|
20218
21116
|
function remove_first(v, l) {
|
|
20219
|
-
|
|
21117
|
+
const str = stringify(v);
|
|
21118
|
+
this.context.memoryLimit.use(str.length);
|
|
21119
|
+
return str.replace(stringify(l), '');
|
|
20220
21120
|
}
|
|
20221
21121
|
function remove_last(v, l) {
|
|
20222
21122
|
const str = stringify(v);
|
|
20223
|
-
|
|
21123
|
+
this.context.memoryLimit.use(str.length);
|
|
21124
|
+
const pattern = stringify(l);
|
|
20224
21125
|
const index = str.lastIndexOf(pattern);
|
|
20225
21126
|
if (index === -1)
|
|
20226
21127
|
return str;
|
|
20227
|
-
return str.substring(0, index) + str.substring(index + pattern.length
|
|
21128
|
+
return str.substring(0, index) + str.substring(index + pattern.length);
|
|
20228
21129
|
}
|
|
20229
21130
|
function rstrip(str, chars) {
|
|
21131
|
+
str = stringify(str);
|
|
21132
|
+
this.context.memoryLimit.use(str.length);
|
|
20230
21133
|
if (chars) {
|
|
20231
21134
|
chars = escapeRegExp(stringify(chars));
|
|
20232
|
-
return
|
|
21135
|
+
return str.replace(new RegExp(`[${chars}]+$`, 'g'), '');
|
|
20233
21136
|
}
|
|
20234
|
-
return
|
|
21137
|
+
return str.replace(/\s+$/, '');
|
|
20235
21138
|
}
|
|
20236
21139
|
function split(v, arg) {
|
|
20237
|
-
const
|
|
21140
|
+
const str = stringify(v);
|
|
21141
|
+
this.context.memoryLimit.use(str.length);
|
|
21142
|
+
const arr = str.split(stringify(arg));
|
|
20238
21143
|
// align to ruby split, which is the behavior of shopify/liquid
|
|
20239
21144
|
// see: https://ruby-doc.org/core-2.4.0/String.html#method-i-split
|
|
20240
21145
|
while (arr.length && arr[arr.length - 1] === '')
|
|
@@ -20242,50 +21147,101 @@ function split(v, arg) {
|
|
|
20242
21147
|
return arr;
|
|
20243
21148
|
}
|
|
20244
21149
|
function strip(v, chars) {
|
|
21150
|
+
const str = stringify(v);
|
|
21151
|
+
this.context.memoryLimit.use(str.length);
|
|
20245
21152
|
if (chars) {
|
|
20246
21153
|
chars = escapeRegExp(stringify(chars));
|
|
20247
|
-
return
|
|
21154
|
+
return str
|
|
20248
21155
|
.replace(new RegExp(`^[${chars}]+`, 'g'), '')
|
|
20249
21156
|
.replace(new RegExp(`[${chars}]+$`, 'g'), '');
|
|
20250
21157
|
}
|
|
20251
|
-
return
|
|
21158
|
+
return str.trim();
|
|
20252
21159
|
}
|
|
20253
21160
|
function strip_newlines(v) {
|
|
20254
|
-
|
|
21161
|
+
const str = stringify(v);
|
|
21162
|
+
this.context.memoryLimit.use(str.length);
|
|
21163
|
+
return str.replace(/\r?\n/gm, '');
|
|
20255
21164
|
}
|
|
20256
21165
|
function capitalize(str) {
|
|
20257
21166
|
str = stringify(str);
|
|
21167
|
+
this.context.memoryLimit.use(str.length);
|
|
20258
21168
|
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
20259
21169
|
}
|
|
20260
21170
|
function replace(v, pattern, replacement) {
|
|
20261
|
-
|
|
21171
|
+
const str = stringify(v);
|
|
21172
|
+
this.context.memoryLimit.use(str.length);
|
|
21173
|
+
return str.split(stringify(pattern)).join(replacement);
|
|
20262
21174
|
}
|
|
20263
21175
|
function replace_first(v, arg1, arg2) {
|
|
20264
|
-
|
|
21176
|
+
const str = stringify(v);
|
|
21177
|
+
this.context.memoryLimit.use(str.length);
|
|
21178
|
+
return str.replace(stringify(arg1), arg2);
|
|
20265
21179
|
}
|
|
20266
21180
|
function replace_last(v, arg1, arg2) {
|
|
20267
21181
|
const str = stringify(v);
|
|
20268
|
-
|
|
21182
|
+
this.context.memoryLimit.use(str.length);
|
|
21183
|
+
const pattern = stringify(arg1);
|
|
20269
21184
|
const index = str.lastIndexOf(pattern);
|
|
20270
21185
|
if (index === -1)
|
|
20271
21186
|
return str;
|
|
20272
|
-
const replacement =
|
|
21187
|
+
const replacement = stringify(arg2);
|
|
20273
21188
|
return str.substring(0, index) + replacement + str.substring(index + pattern.length);
|
|
20274
21189
|
}
|
|
20275
21190
|
function truncate(v, l = 50, o = '...') {
|
|
20276
|
-
|
|
20277
|
-
|
|
21191
|
+
const str = stringify(v);
|
|
21192
|
+
this.context.memoryLimit.use(str.length);
|
|
21193
|
+
if (str.length <= l)
|
|
20278
21194
|
return v;
|
|
20279
|
-
return
|
|
21195
|
+
return str.substring(0, l - o.length) + o;
|
|
20280
21196
|
}
|
|
20281
21197
|
function truncatewords(v, words = 15, o = '...') {
|
|
20282
|
-
const
|
|
21198
|
+
const str = stringify(v);
|
|
21199
|
+
this.context.memoryLimit.use(str.length);
|
|
21200
|
+
const arr = str.split(/\s+/);
|
|
20283
21201
|
if (words <= 0)
|
|
20284
21202
|
words = 1;
|
|
20285
21203
|
let ret = arr.slice(0, words).join(' ');
|
|
20286
21204
|
if (arr.length >= words)
|
|
20287
21205
|
ret += o;
|
|
20288
21206
|
return ret;
|
|
21207
|
+
}
|
|
21208
|
+
function normalize_whitespace(v) {
|
|
21209
|
+
const str = stringify(v);
|
|
21210
|
+
this.context.memoryLimit.use(str.length);
|
|
21211
|
+
return str.replace(/\s+/g, ' ');
|
|
21212
|
+
}
|
|
21213
|
+
function number_of_words(input, mode) {
|
|
21214
|
+
const str = stringify(input);
|
|
21215
|
+
this.context.memoryLimit.use(str.length);
|
|
21216
|
+
input = str.trim();
|
|
21217
|
+
if (!input)
|
|
21218
|
+
return 0;
|
|
21219
|
+
switch (mode) {
|
|
21220
|
+
case 'cjk':
|
|
21221
|
+
// Count CJK characters and words
|
|
21222
|
+
return (input.match(rCJKWord) || []).length + (input.match(rNonCJKWord) || []).length;
|
|
21223
|
+
case 'auto':
|
|
21224
|
+
// Count CJK characters, if none, count words
|
|
21225
|
+
return rCJKWord.test(input)
|
|
21226
|
+
? input.match(rCJKWord).length + (input.match(rNonCJKWord) || []).length
|
|
21227
|
+
: input.split(/\s+/).length;
|
|
21228
|
+
default:
|
|
21229
|
+
// Count words only
|
|
21230
|
+
return input.split(/\s+/).length;
|
|
21231
|
+
}
|
|
21232
|
+
}
|
|
21233
|
+
function array_to_sentence_string(array, connector = 'and') {
|
|
21234
|
+
this.context.memoryLimit.use(array.length);
|
|
21235
|
+
switch (array.length) {
|
|
21236
|
+
case 0:
|
|
21237
|
+
return '';
|
|
21238
|
+
case 1:
|
|
21239
|
+
return array[0];
|
|
21240
|
+
case 2:
|
|
21241
|
+
return `${array[0]} ${connector} ${array[1]}`;
|
|
21242
|
+
default:
|
|
21243
|
+
return `${array.slice(0, -1).join(', ')}, ${connector} ${array[array.length - 1]}`;
|
|
21244
|
+
}
|
|
20289
21245
|
}
|
|
20290
21246
|
|
|
20291
21247
|
var stringFilters = /*#__PURE__*/Object.freeze({
|
|
@@ -20307,52 +21263,58 @@ var stringFilters = /*#__PURE__*/Object.freeze({
|
|
|
20307
21263
|
replace_first: replace_first,
|
|
20308
21264
|
replace_last: replace_last,
|
|
20309
21265
|
truncate: truncate,
|
|
20310
|
-
truncatewords: truncatewords
|
|
21266
|
+
truncatewords: truncatewords,
|
|
21267
|
+
normalize_whitespace: normalize_whitespace,
|
|
21268
|
+
number_of_words: number_of_words,
|
|
21269
|
+
array_to_sentence_string: array_to_sentence_string
|
|
20311
21270
|
});
|
|
20312
21271
|
|
|
20313
|
-
const filters = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, htmlFilters), mathFilters), urlFilters), arrayFilters), dateFilters), stringFilters),
|
|
20314
|
-
raw, default: Default });
|
|
21272
|
+
const filters = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, htmlFilters), mathFilters), urlFilters), arrayFilters), dateFilters), stringFilters), misc);
|
|
20315
21273
|
|
|
20316
21274
|
class AssignTag extends Tag {
|
|
20317
21275
|
constructor(token, remainTokens, liquid) {
|
|
20318
21276
|
super(token, remainTokens, liquid);
|
|
20319
|
-
|
|
20320
|
-
this.key =
|
|
20321
|
-
tokenizer.
|
|
20322
|
-
|
|
20323
|
-
tokenizer.
|
|
20324
|
-
this.
|
|
21277
|
+
this.identifier = this.tokenizer.readIdentifier();
|
|
21278
|
+
this.key = this.identifier.content;
|
|
21279
|
+
this.tokenizer.assert(this.key, 'expected variable name');
|
|
21280
|
+
this.tokenizer.skipBlank();
|
|
21281
|
+
this.tokenizer.assert(this.tokenizer.peek() === '=', 'expected "="');
|
|
21282
|
+
this.tokenizer.advance();
|
|
21283
|
+
this.value = new Value(this.tokenizer.readFilteredValue(), this.liquid);
|
|
20325
21284
|
}
|
|
20326
21285
|
*render(ctx) {
|
|
20327
21286
|
ctx.bottom()[this.key] = yield this.value.value(ctx, this.liquid.options.lenientIf);
|
|
20328
21287
|
}
|
|
21288
|
+
*arguments() {
|
|
21289
|
+
yield this.value;
|
|
21290
|
+
}
|
|
21291
|
+
*localScope() {
|
|
21292
|
+
yield this.identifier;
|
|
21293
|
+
}
|
|
20329
21294
|
}
|
|
20330
21295
|
|
|
20331
21296
|
const MODIFIERS = ['offset', 'limit', 'reversed'];
|
|
20332
21297
|
class ForTag extends Tag {
|
|
20333
|
-
constructor(token, remainTokens, liquid) {
|
|
21298
|
+
constructor(token, remainTokens, liquid, parser) {
|
|
20334
21299
|
super(token, remainTokens, liquid);
|
|
20335
|
-
const
|
|
20336
|
-
const
|
|
20337
|
-
const
|
|
20338
|
-
const collection = tokenizer.readValue();
|
|
21300
|
+
const variable = this.tokenizer.readIdentifier();
|
|
21301
|
+
const inStr = this.tokenizer.readIdentifier();
|
|
21302
|
+
const collection = this.tokenizer.readValue();
|
|
20339
21303
|
if (!variable.size() || inStr.content !== 'in' || !collection) {
|
|
20340
21304
|
throw new Error(`illegal tag: ${token.getText()}`);
|
|
20341
21305
|
}
|
|
20342
21306
|
this.variable = variable.content;
|
|
20343
21307
|
this.collection = collection;
|
|
20344
|
-
this.hash = new Hash(tokenizer.
|
|
21308
|
+
this.hash = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
|
|
20345
21309
|
this.templates = [];
|
|
20346
21310
|
this.elseTemplates = [];
|
|
20347
21311
|
let p;
|
|
20348
|
-
const stream =
|
|
21312
|
+
const stream = parser.parseStream(remainTokens)
|
|
20349
21313
|
.on('start', () => (p = this.templates))
|
|
20350
|
-
.on('tag:else',
|
|
20351
|
-
.on('tag:endfor', ()
|
|
21314
|
+
.on('tag:else', tag => { assertEmpty(tag.args); p = this.elseTemplates; })
|
|
21315
|
+
.on('tag:endfor', tag => { assertEmpty(tag.args); stream.stop(); })
|
|
20352
21316
|
.on('template', (tpl) => p.push(tpl))
|
|
20353
|
-
.on('end', () => {
|
|
20354
|
-
throw new Error(`tag ${token.getText()} not closed`);
|
|
20355
|
-
});
|
|
21317
|
+
.on('end', () => { throw new Error(`tag ${token.getText()} not closed`); });
|
|
20356
21318
|
stream.start();
|
|
20357
21319
|
}
|
|
20358
21320
|
*render(ctx, emitter) {
|
|
@@ -20381,16 +21343,33 @@ class ForTag extends Tag {
|
|
|
20381
21343
|
ctx.push(scope);
|
|
20382
21344
|
for (const item of collection) {
|
|
20383
21345
|
scope[this.variable] = item;
|
|
21346
|
+
ctx.continueCalled = ctx.breakCalled = false;
|
|
20384
21347
|
yield r.renderTemplates(this.templates, ctx, emitter);
|
|
20385
|
-
if (
|
|
20386
|
-
emitter['break'] = false;
|
|
21348
|
+
if (ctx.breakCalled)
|
|
20387
21349
|
break;
|
|
20388
|
-
}
|
|
20389
|
-
emitter['continue'] = false;
|
|
20390
21350
|
scope.forloop.next();
|
|
20391
21351
|
}
|
|
21352
|
+
ctx.continueCalled = ctx.breakCalled = false;
|
|
20392
21353
|
ctx.pop();
|
|
20393
21354
|
}
|
|
21355
|
+
*children() {
|
|
21356
|
+
const templates = this.templates.slice();
|
|
21357
|
+
if (this.elseTemplates) {
|
|
21358
|
+
templates.push(...this.elseTemplates);
|
|
21359
|
+
}
|
|
21360
|
+
return templates;
|
|
21361
|
+
}
|
|
21362
|
+
*arguments() {
|
|
21363
|
+
yield this.collection;
|
|
21364
|
+
for (const v of Object.values(this.hash.hash)) {
|
|
21365
|
+
if (isValueToken(v)) {
|
|
21366
|
+
yield v;
|
|
21367
|
+
}
|
|
21368
|
+
}
|
|
21369
|
+
}
|
|
21370
|
+
blockScope() {
|
|
21371
|
+
return [this.variable, 'forloop'];
|
|
21372
|
+
}
|
|
20394
21373
|
}
|
|
20395
21374
|
function reversed(arr) {
|
|
20396
21375
|
return [...arr].reverse();
|
|
@@ -20403,60 +21382,82 @@ function limit(arr, count) {
|
|
|
20403
21382
|
}
|
|
20404
21383
|
|
|
20405
21384
|
class CaptureTag extends Tag {
|
|
20406
|
-
constructor(tagToken, remainTokens, liquid) {
|
|
21385
|
+
constructor(tagToken, remainTokens, liquid, parser) {
|
|
20407
21386
|
super(tagToken, remainTokens, liquid);
|
|
20408
21387
|
this.templates = [];
|
|
20409
|
-
|
|
20410
|
-
this.variable =
|
|
20411
|
-
assert(this.variable, () => `${tagToken.args} not valid identifier`);
|
|
21388
|
+
this.identifier = this.readVariable();
|
|
21389
|
+
this.variable = this.identifier.content;
|
|
20412
21390
|
while (remainTokens.length) {
|
|
20413
21391
|
const token = remainTokens.shift();
|
|
20414
21392
|
if (isTagToken(token) && token.name === 'endcapture')
|
|
20415
21393
|
return;
|
|
20416
|
-
this.templates.push(
|
|
21394
|
+
this.templates.push(parser.parseToken(token, remainTokens));
|
|
20417
21395
|
}
|
|
20418
21396
|
throw new Error(`tag ${tagToken.getText()} not closed`);
|
|
20419
21397
|
}
|
|
21398
|
+
readVariable() {
|
|
21399
|
+
let ident = this.tokenizer.readIdentifier();
|
|
21400
|
+
if (ident.content)
|
|
21401
|
+
return ident;
|
|
21402
|
+
ident = this.tokenizer.readQuoted();
|
|
21403
|
+
if (ident)
|
|
21404
|
+
return ident;
|
|
21405
|
+
throw this.tokenizer.error('invalid capture name');
|
|
21406
|
+
}
|
|
20420
21407
|
*render(ctx) {
|
|
20421
21408
|
const r = this.liquid.renderer;
|
|
20422
21409
|
const html = yield r.renderTemplates(this.templates, ctx);
|
|
20423
21410
|
ctx.bottom()[this.variable] = html;
|
|
20424
21411
|
}
|
|
20425
|
-
|
|
20426
|
-
|
|
20427
|
-
|
|
20428
|
-
|
|
20429
|
-
|
|
20430
|
-
|
|
20431
|
-
if (quoted)
|
|
20432
|
-
return evalQuotedToken(quoted);
|
|
21412
|
+
*children() {
|
|
21413
|
+
return this.templates;
|
|
21414
|
+
}
|
|
21415
|
+
*localScope() {
|
|
21416
|
+
yield this.identifier;
|
|
21417
|
+
}
|
|
20433
21418
|
}
|
|
20434
21419
|
|
|
20435
21420
|
class CaseTag extends Tag {
|
|
20436
|
-
constructor(tagToken, remainTokens, liquid) {
|
|
21421
|
+
constructor(tagToken, remainTokens, liquid, parser) {
|
|
20437
21422
|
super(tagToken, remainTokens, liquid);
|
|
20438
21423
|
this.branches = [];
|
|
20439
21424
|
this.elseTemplates = [];
|
|
20440
|
-
this.value = new Value(
|
|
21425
|
+
this.value = new Value(this.tokenizer.readFilteredValue(), this.liquid);
|
|
20441
21426
|
this.elseTemplates = [];
|
|
20442
21427
|
let p = [];
|
|
20443
|
-
|
|
21428
|
+
let elseCount = 0;
|
|
21429
|
+
const stream = parser.parseStream(remainTokens)
|
|
20444
21430
|
.on('tag:when', (token) => {
|
|
21431
|
+
if (elseCount > 0) {
|
|
21432
|
+
return;
|
|
21433
|
+
}
|
|
20445
21434
|
p = [];
|
|
20446
|
-
const tokenizer = new Tokenizer(token.args, this.liquid.options.operators);
|
|
20447
21435
|
const values = [];
|
|
20448
|
-
while (!tokenizer.end()) {
|
|
20449
|
-
values.push(tokenizer.readValueOrThrow());
|
|
20450
|
-
tokenizer.
|
|
21436
|
+
while (!token.tokenizer.end()) {
|
|
21437
|
+
values.push(token.tokenizer.readValueOrThrow());
|
|
21438
|
+
token.tokenizer.skipBlank();
|
|
21439
|
+
if (token.tokenizer.peek() === ',') {
|
|
21440
|
+
token.tokenizer.readTo(',');
|
|
21441
|
+
}
|
|
21442
|
+
else {
|
|
21443
|
+
token.tokenizer.readTo('or');
|
|
21444
|
+
}
|
|
20451
21445
|
}
|
|
20452
21446
|
this.branches.push({
|
|
20453
21447
|
values,
|
|
20454
21448
|
templates: p
|
|
20455
21449
|
});
|
|
20456
21450
|
})
|
|
20457
|
-
.on('tag:else', () =>
|
|
21451
|
+
.on('tag:else', () => {
|
|
21452
|
+
elseCount++;
|
|
21453
|
+
p = this.elseTemplates;
|
|
21454
|
+
})
|
|
20458
21455
|
.on('tag:endcase', () => stream.stop())
|
|
20459
|
-
.on('template', (tpl) =>
|
|
21456
|
+
.on('template', (tpl) => {
|
|
21457
|
+
if (p !== this.elseTemplates || elseCount === 1) {
|
|
21458
|
+
p.push(tpl);
|
|
21459
|
+
}
|
|
21460
|
+
})
|
|
20460
21461
|
.on('end', () => {
|
|
20461
21462
|
throw new Error(`tag ${tagToken.getText()} not closed`);
|
|
20462
21463
|
});
|
|
@@ -20469,7 +21470,7 @@ class CaseTag extends Tag {
|
|
|
20469
21470
|
for (const branch of this.branches) {
|
|
20470
21471
|
for (const valueToken of branch.values) {
|
|
20471
21472
|
const value = yield evalToken(valueToken, ctx, ctx.opts.lenientIf);
|
|
20472
|
-
if (target
|
|
21473
|
+
if (equals(target, value)) {
|
|
20473
21474
|
yield r.renderTemplates(branch.templates, ctx, emitter);
|
|
20474
21475
|
branchHit = true;
|
|
20475
21476
|
break;
|
|
@@ -20480,6 +21481,17 @@ class CaseTag extends Tag {
|
|
|
20480
21481
|
yield r.renderTemplates(this.elseTemplates, ctx, emitter);
|
|
20481
21482
|
}
|
|
20482
21483
|
}
|
|
21484
|
+
*arguments() {
|
|
21485
|
+
yield this.value;
|
|
21486
|
+
yield* this.branches.flatMap(b => b.values);
|
|
21487
|
+
}
|
|
21488
|
+
*children() {
|
|
21489
|
+
const templates = this.branches.flatMap(b => b.templates);
|
|
21490
|
+
if (this.elseTemplates) {
|
|
21491
|
+
templates.push(...this.elseTemplates);
|
|
21492
|
+
}
|
|
21493
|
+
return templates;
|
|
21494
|
+
}
|
|
20483
21495
|
}
|
|
20484
21496
|
|
|
20485
21497
|
class CommentTag extends Tag {
|
|
@@ -20496,11 +21508,10 @@ class CommentTag extends Tag {
|
|
|
20496
21508
|
}
|
|
20497
21509
|
|
|
20498
21510
|
class RenderTag extends Tag {
|
|
20499
|
-
constructor(token, remainTokens, liquid) {
|
|
21511
|
+
constructor(token, remainTokens, liquid, parser) {
|
|
20500
21512
|
super(token, remainTokens, liquid);
|
|
20501
|
-
const
|
|
20502
|
-
|
|
20503
|
-
this.file = parseFilePath(tokenizer, this.liquid);
|
|
21513
|
+
const tokenizer = this.tokenizer;
|
|
21514
|
+
this.file = parseFilePath(tokenizer, this.liquid, parser);
|
|
20504
21515
|
this.currentFile = token.file;
|
|
20505
21516
|
while (!tokenizer.end()) {
|
|
20506
21517
|
tokenizer.skipBlank();
|
|
@@ -20534,13 +21545,13 @@ class RenderTag extends Tag {
|
|
|
20534
21545
|
tokenizer.p = begin;
|
|
20535
21546
|
break;
|
|
20536
21547
|
}
|
|
20537
|
-
this.hash = new Hash(tokenizer.
|
|
21548
|
+
this.hash = new Hash(tokenizer, liquid.options.keyValueSeparator);
|
|
20538
21549
|
}
|
|
20539
21550
|
*render(ctx, emitter) {
|
|
20540
21551
|
const { liquid, hash } = this;
|
|
20541
21552
|
const filepath = (yield renderFilePath(this['file'], ctx, liquid));
|
|
20542
|
-
assert(filepath, () => `illegal
|
|
20543
|
-
const childCtx =
|
|
21553
|
+
assert(filepath, () => `illegal file path "${filepath}"`);
|
|
21554
|
+
const childCtx = ctx.spawn();
|
|
20544
21555
|
const scope = childCtx.bottom();
|
|
20545
21556
|
__assign(scope, yield hash.render(ctx));
|
|
20546
21557
|
if (this['with']) {
|
|
@@ -20563,6 +21574,55 @@ class RenderTag extends Tag {
|
|
|
20563
21574
|
yield liquid.renderer.renderTemplates(templates, childCtx, emitter);
|
|
20564
21575
|
}
|
|
20565
21576
|
}
|
|
21577
|
+
*children(partials, sync) {
|
|
21578
|
+
if (partials && isString(this['file'])) {
|
|
21579
|
+
return (yield this.liquid._parsePartialFile(this['file'], sync, this['currentFile']));
|
|
21580
|
+
}
|
|
21581
|
+
return [];
|
|
21582
|
+
}
|
|
21583
|
+
partialScope() {
|
|
21584
|
+
if (isString(this['file'])) {
|
|
21585
|
+
const names = Object.keys(this.hash.hash);
|
|
21586
|
+
if (this['with']) {
|
|
21587
|
+
const { value, alias } = this['with'];
|
|
21588
|
+
if (isString(alias)) {
|
|
21589
|
+
names.push([alias, value]);
|
|
21590
|
+
}
|
|
21591
|
+
else if (isString(this.file)) {
|
|
21592
|
+
names.push([this.file, value]);
|
|
21593
|
+
}
|
|
21594
|
+
}
|
|
21595
|
+
if (this['for']) {
|
|
21596
|
+
const { value, alias } = this['for'];
|
|
21597
|
+
if (isString(alias)) {
|
|
21598
|
+
names.push([alias, value]);
|
|
21599
|
+
}
|
|
21600
|
+
else if (isString(this.file)) {
|
|
21601
|
+
names.push([this.file, value]);
|
|
21602
|
+
}
|
|
21603
|
+
}
|
|
21604
|
+
return { name: this['file'], isolated: true, scope: names };
|
|
21605
|
+
}
|
|
21606
|
+
}
|
|
21607
|
+
*arguments() {
|
|
21608
|
+
for (const v of Object.values(this.hash.hash)) {
|
|
21609
|
+
if (isValueToken(v)) {
|
|
21610
|
+
yield v;
|
|
21611
|
+
}
|
|
21612
|
+
}
|
|
21613
|
+
if (this['with']) {
|
|
21614
|
+
const { value } = this['with'];
|
|
21615
|
+
if (isValueToken(value)) {
|
|
21616
|
+
yield value;
|
|
21617
|
+
}
|
|
21618
|
+
}
|
|
21619
|
+
if (this['for']) {
|
|
21620
|
+
const { value } = this['for'];
|
|
21621
|
+
if (isValueToken(value)) {
|
|
21622
|
+
yield value;
|
|
21623
|
+
}
|
|
21624
|
+
}
|
|
21625
|
+
}
|
|
20566
21626
|
}
|
|
20567
21627
|
/**
|
|
20568
21628
|
* @return null for "none",
|
|
@@ -20570,22 +21630,21 @@ class RenderTag extends Tag {
|
|
|
20570
21630
|
* @return Token for expression (not quoted)
|
|
20571
21631
|
* @throws TypeError if cannot read next token
|
|
20572
21632
|
*/
|
|
20573
|
-
function parseFilePath(tokenizer, liquid) {
|
|
21633
|
+
function parseFilePath(tokenizer, liquid, parser) {
|
|
20574
21634
|
if (liquid.options.dynamicPartials) {
|
|
20575
21635
|
const file = tokenizer.readValue();
|
|
20576
|
-
|
|
20577
|
-
throw new TypeError(`illegal argument "${tokenizer.input}"`);
|
|
21636
|
+
tokenizer.assert(file, 'illegal file path');
|
|
20578
21637
|
if (file.getText() === 'none')
|
|
20579
21638
|
return;
|
|
20580
21639
|
if (isQuotedToken(file)) {
|
|
20581
21640
|
// for filenames like "files/{{file}}", eval as liquid template
|
|
20582
|
-
const templates =
|
|
21641
|
+
const templates = parser.parse(evalQuotedToken(file));
|
|
20583
21642
|
return optimize(templates);
|
|
20584
21643
|
}
|
|
20585
21644
|
return file;
|
|
20586
21645
|
}
|
|
20587
21646
|
const tokens = [...tokenizer.readFileNameTemplate(liquid.options)];
|
|
20588
|
-
const templates = optimize(
|
|
21647
|
+
const templates = optimize(parser.parseTokens(tokens));
|
|
20589
21648
|
return templates === 'none' ? undefined : templates;
|
|
20590
21649
|
}
|
|
20591
21650
|
function optimize(templates) {
|
|
@@ -20603,11 +21662,10 @@ function* renderFilePath(file, ctx, liquid) {
|
|
|
20603
21662
|
}
|
|
20604
21663
|
|
|
20605
21664
|
class IncludeTag extends Tag {
|
|
20606
|
-
constructor(token, remainTokens, liquid) {
|
|
21665
|
+
constructor(token, remainTokens, liquid, parser) {
|
|
20607
21666
|
super(token, remainTokens, liquid);
|
|
20608
|
-
const
|
|
20609
|
-
|
|
20610
|
-
this['file'] = parseFilePath(tokenizer, this.liquid);
|
|
21667
|
+
const { tokenizer } = token;
|
|
21668
|
+
this['file'] = parseFilePath(tokenizer, this.liquid, parser);
|
|
20611
21669
|
this['currentFile'] = token.file;
|
|
20612
21670
|
const begin = tokenizer.p;
|
|
20613
21671
|
const withStr = tokenizer.readIdentifier();
|
|
@@ -20621,13 +21679,13 @@ class IncludeTag extends Tag {
|
|
|
20621
21679
|
}
|
|
20622
21680
|
else
|
|
20623
21681
|
tokenizer.p = begin;
|
|
20624
|
-
this.hash = new Hash(tokenizer
|
|
21682
|
+
this.hash = new Hash(tokenizer, liquid.options.jekyllInclude || liquid.options.keyValueSeparator);
|
|
20625
21683
|
}
|
|
20626
21684
|
*render(ctx, emitter) {
|
|
20627
21685
|
const { liquid, hash, withVar } = this;
|
|
20628
21686
|
const { renderer } = liquid;
|
|
20629
21687
|
const filepath = (yield renderFilePath(this['file'], ctx, liquid));
|
|
20630
|
-
assert(filepath, () => `illegal
|
|
21688
|
+
assert(filepath, () => `illegal file path "${filepath}"`);
|
|
20631
21689
|
const saved = ctx.saveRegister('blocks', 'blockMode');
|
|
20632
21690
|
ctx.setRegister('blocks', {});
|
|
20633
21691
|
ctx.setRegister('blockMode', BlockMode.OUTPUT);
|
|
@@ -20640,13 +21698,43 @@ class IncludeTag extends Tag {
|
|
|
20640
21698
|
ctx.pop();
|
|
20641
21699
|
ctx.restoreRegister(saved);
|
|
20642
21700
|
}
|
|
21701
|
+
*children(partials, sync) {
|
|
21702
|
+
if (partials && isString(this['file'])) {
|
|
21703
|
+
return (yield this.liquid._parsePartialFile(this['file'], sync, this['currentFile']));
|
|
21704
|
+
}
|
|
21705
|
+
return [];
|
|
21706
|
+
}
|
|
21707
|
+
partialScope() {
|
|
21708
|
+
if (isString(this['file'])) {
|
|
21709
|
+
let names;
|
|
21710
|
+
if (this.liquid.options.jekyllInclude) {
|
|
21711
|
+
names = ['include'];
|
|
21712
|
+
}
|
|
21713
|
+
else {
|
|
21714
|
+
names = Object.keys(this.hash.hash);
|
|
21715
|
+
if (this.withVar) {
|
|
21716
|
+
names.push([this['file'], this.withVar]);
|
|
21717
|
+
}
|
|
21718
|
+
}
|
|
21719
|
+
return { name: this['file'], isolated: false, scope: names };
|
|
21720
|
+
}
|
|
21721
|
+
}
|
|
21722
|
+
*arguments() {
|
|
21723
|
+
yield* Object.values(this.hash.hash).filter(isValueToken);
|
|
21724
|
+
if (isValueToken(this['file'])) {
|
|
21725
|
+
yield this['file'];
|
|
21726
|
+
}
|
|
21727
|
+
if (isValueToken(this.withVar)) {
|
|
21728
|
+
yield this.withVar;
|
|
21729
|
+
}
|
|
21730
|
+
}
|
|
20643
21731
|
}
|
|
20644
21732
|
|
|
20645
21733
|
class DecrementTag extends Tag {
|
|
20646
21734
|
constructor(token, remainTokens, liquid) {
|
|
20647
21735
|
super(token, remainTokens, liquid);
|
|
20648
|
-
|
|
20649
|
-
this.variable =
|
|
21736
|
+
this.identifier = this.tokenizer.readIdentifier();
|
|
21737
|
+
this.variable = this.identifier.content;
|
|
20650
21738
|
}
|
|
20651
21739
|
render(context, emitter) {
|
|
20652
21740
|
const scope = context.environments;
|
|
@@ -20655,30 +21743,32 @@ class DecrementTag extends Tag {
|
|
|
20655
21743
|
}
|
|
20656
21744
|
emitter.write(stringify(--scope[this.variable]));
|
|
20657
21745
|
}
|
|
21746
|
+
*localScope() {
|
|
21747
|
+
yield this.identifier;
|
|
21748
|
+
}
|
|
20658
21749
|
}
|
|
20659
21750
|
|
|
20660
21751
|
class CycleTag extends Tag {
|
|
20661
|
-
constructor(
|
|
20662
|
-
super(
|
|
21752
|
+
constructor(token, remainTokens, liquid) {
|
|
21753
|
+
super(token, remainTokens, liquid);
|
|
20663
21754
|
this.candidates = [];
|
|
20664
|
-
const
|
|
20665
|
-
|
|
20666
|
-
tokenizer.skipBlank();
|
|
21755
|
+
const group = this.tokenizer.readValue();
|
|
21756
|
+
this.tokenizer.skipBlank();
|
|
20667
21757
|
if (group) {
|
|
20668
|
-
if (tokenizer.peek() === ':') {
|
|
21758
|
+
if (this.tokenizer.peek() === ':') {
|
|
20669
21759
|
this.group = group;
|
|
20670
|
-
tokenizer.advance();
|
|
21760
|
+
this.tokenizer.advance();
|
|
20671
21761
|
}
|
|
20672
21762
|
else
|
|
20673
21763
|
this.candidates.push(group);
|
|
20674
21764
|
}
|
|
20675
|
-
while (!tokenizer.end()) {
|
|
20676
|
-
const value = tokenizer.readValue();
|
|
21765
|
+
while (!this.tokenizer.end()) {
|
|
21766
|
+
const value = this.tokenizer.readValue();
|
|
20677
21767
|
if (value)
|
|
20678
21768
|
this.candidates.push(value);
|
|
20679
|
-
tokenizer.readTo(',');
|
|
21769
|
+
this.tokenizer.readTo(',');
|
|
20680
21770
|
}
|
|
20681
|
-
assert(this.candidates.length, () => `empty candidates: ${
|
|
21771
|
+
this.tokenizer.assert(this.candidates.length, () => `empty candidates: "${token.getText()}"`);
|
|
20682
21772
|
}
|
|
20683
21773
|
*render(ctx, emitter) {
|
|
20684
21774
|
const group = (yield evalToken(this.group, ctx));
|
|
@@ -20693,25 +21783,37 @@ class CycleTag extends Tag {
|
|
|
20693
21783
|
groups[fingerprint] = idx;
|
|
20694
21784
|
return yield evalToken(candidate, ctx);
|
|
20695
21785
|
}
|
|
21786
|
+
*arguments() {
|
|
21787
|
+
yield* this.candidates;
|
|
21788
|
+
if (this.group) {
|
|
21789
|
+
yield this.group;
|
|
21790
|
+
}
|
|
21791
|
+
}
|
|
20696
21792
|
}
|
|
20697
21793
|
|
|
20698
21794
|
class IfTag extends Tag {
|
|
20699
|
-
constructor(tagToken, remainTokens, liquid) {
|
|
21795
|
+
constructor(tagToken, remainTokens, liquid, parser) {
|
|
20700
21796
|
super(tagToken, remainTokens, liquid);
|
|
20701
21797
|
this.branches = [];
|
|
20702
|
-
|
|
20703
|
-
|
|
20704
|
-
liquid.parser.parseStream(remainTokens)
|
|
21798
|
+
let p = [];
|
|
21799
|
+
parser.parseStream(remainTokens)
|
|
20705
21800
|
.on('start', () => this.branches.push({
|
|
20706
|
-
value: new Value(tagToken.
|
|
20707
|
-
templates: (p = [])
|
|
20708
|
-
}))
|
|
20709
|
-
.on('tag:elsif', (token) => this.branches.push({
|
|
20710
|
-
value: new Value(token.args, this.liquid),
|
|
21801
|
+
value: new Value(tagToken.tokenizer.readFilteredValue(), this.liquid),
|
|
20711
21802
|
templates: (p = [])
|
|
20712
21803
|
}))
|
|
20713
|
-
.on('tag:
|
|
20714
|
-
.
|
|
21804
|
+
.on('tag:elsif', (token) => {
|
|
21805
|
+
assert(!this.elseTemplates, 'unexpected elsif after else');
|
|
21806
|
+
this.branches.push({
|
|
21807
|
+
value: new Value(token.tokenizer.readFilteredValue(), this.liquid),
|
|
21808
|
+
templates: (p = [])
|
|
21809
|
+
});
|
|
21810
|
+
})
|
|
21811
|
+
.on('tag:else', tag => {
|
|
21812
|
+
assertEmpty(tag.args);
|
|
21813
|
+
assert(!this.elseTemplates, 'duplicated else');
|
|
21814
|
+
p = this.elseTemplates = [];
|
|
21815
|
+
})
|
|
21816
|
+
.on('tag:endif', function (tag) { assertEmpty(tag.args); this.stop(); })
|
|
20715
21817
|
.on('template', (tpl) => p.push(tpl))
|
|
20716
21818
|
.on('end', () => { throw new Error(`tag ${tagToken.getText()} not closed`); })
|
|
20717
21819
|
.start();
|
|
@@ -20725,15 +21827,25 @@ class IfTag extends Tag {
|
|
|
20725
21827
|
return;
|
|
20726
21828
|
}
|
|
20727
21829
|
}
|
|
20728
|
-
yield r.renderTemplates(this.elseTemplates, ctx, emitter);
|
|
21830
|
+
yield r.renderTemplates(this.elseTemplates || [], ctx, emitter);
|
|
21831
|
+
}
|
|
21832
|
+
*children() {
|
|
21833
|
+
const templates = this.branches.flatMap(b => b.templates);
|
|
21834
|
+
if (this.elseTemplates) {
|
|
21835
|
+
templates.push(...this.elseTemplates);
|
|
21836
|
+
}
|
|
21837
|
+
return templates;
|
|
21838
|
+
}
|
|
21839
|
+
arguments() {
|
|
21840
|
+
return this.branches.map(b => b.value);
|
|
20729
21841
|
}
|
|
20730
21842
|
}
|
|
20731
21843
|
|
|
20732
21844
|
class IncrementTag extends Tag {
|
|
20733
21845
|
constructor(token, remainTokens, liquid) {
|
|
20734
21846
|
super(token, remainTokens, liquid);
|
|
20735
|
-
|
|
20736
|
-
this.variable =
|
|
21847
|
+
this.identifier = this.tokenizer.readIdentifier();
|
|
21848
|
+
this.variable = this.identifier.content;
|
|
20737
21849
|
}
|
|
20738
21850
|
render(context, emitter) {
|
|
20739
21851
|
const scope = context.environments;
|
|
@@ -20744,16 +21856,18 @@ class IncrementTag extends Tag {
|
|
|
20744
21856
|
scope[this.variable]++;
|
|
20745
21857
|
emitter.write(stringify(val));
|
|
20746
21858
|
}
|
|
21859
|
+
*localScope() {
|
|
21860
|
+
yield this.identifier;
|
|
21861
|
+
}
|
|
20747
21862
|
}
|
|
20748
21863
|
|
|
20749
21864
|
class LayoutTag extends Tag {
|
|
20750
|
-
constructor(token, remainTokens, liquid) {
|
|
21865
|
+
constructor(token, remainTokens, liquid, parser) {
|
|
20751
21866
|
super(token, remainTokens, liquid);
|
|
20752
|
-
|
|
20753
|
-
this.file = parseFilePath(tokenizer, this.liquid);
|
|
21867
|
+
this.file = parseFilePath(this.tokenizer, this.liquid, parser);
|
|
20754
21868
|
this['currentFile'] = token.file;
|
|
20755
|
-
this.args = new Hash(tokenizer.
|
|
20756
|
-
this.templates =
|
|
21869
|
+
this.args = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
|
|
21870
|
+
this.templates = parser.parseTokens(remainTokens);
|
|
20757
21871
|
}
|
|
20758
21872
|
*render(ctx, emitter) {
|
|
20759
21873
|
const { liquid, args, file } = this;
|
|
@@ -20764,7 +21878,7 @@ class LayoutTag extends Tag {
|
|
|
20764
21878
|
return;
|
|
20765
21879
|
}
|
|
20766
21880
|
const filepath = (yield renderFilePath(this.file, ctx, liquid));
|
|
20767
|
-
assert(filepath, () => `illegal
|
|
21881
|
+
assert(filepath, () => `illegal file path "${filepath}"`);
|
|
20768
21882
|
const templates = (yield liquid._parseLayoutFile(filepath, ctx.sync, this['currentFile']));
|
|
20769
21883
|
// render remaining contents and store rendered results
|
|
20770
21884
|
ctx.setRegister('blockMode', BlockMode.STORE);
|
|
@@ -20779,10 +21893,32 @@ class LayoutTag extends Tag {
|
|
|
20779
21893
|
yield renderer.renderTemplates(templates, ctx, emitter);
|
|
20780
21894
|
ctx.pop();
|
|
20781
21895
|
}
|
|
21896
|
+
*children(partials) {
|
|
21897
|
+
const templates = this.templates.slice();
|
|
21898
|
+
if (partials && isString(this.file)) {
|
|
21899
|
+
templates.push(...(yield this.liquid._parsePartialFile(this.file, true, this['currentFile'])));
|
|
21900
|
+
}
|
|
21901
|
+
return templates;
|
|
21902
|
+
}
|
|
21903
|
+
*arguments() {
|
|
21904
|
+
for (const v of Object.values(this.args.hash)) {
|
|
21905
|
+
if (isValueToken(v)) {
|
|
21906
|
+
yield v;
|
|
21907
|
+
}
|
|
21908
|
+
}
|
|
21909
|
+
if (isValueToken(this.file)) {
|
|
21910
|
+
yield this.file;
|
|
21911
|
+
}
|
|
21912
|
+
}
|
|
21913
|
+
partialScope() {
|
|
21914
|
+
if (isString(this.file)) {
|
|
21915
|
+
return { name: this.file, isolated: false, scope: Object.keys(this.args.hash) };
|
|
21916
|
+
}
|
|
21917
|
+
}
|
|
20782
21918
|
}
|
|
20783
21919
|
|
|
20784
21920
|
class BlockTag extends Tag {
|
|
20785
|
-
constructor(token, remainTokens, liquid) {
|
|
21921
|
+
constructor(token, remainTokens, liquid, parser) {
|
|
20786
21922
|
super(token, remainTokens, liquid);
|
|
20787
21923
|
this.templates = [];
|
|
20788
21924
|
const match = /\w+/.exec(token.args);
|
|
@@ -20791,7 +21927,7 @@ class BlockTag extends Tag {
|
|
|
20791
21927
|
const token = remainTokens.shift();
|
|
20792
21928
|
if (isTagToken(token) && token.name === 'endblock')
|
|
20793
21929
|
return;
|
|
20794
|
-
const template =
|
|
21930
|
+
const template = parser.parseToken(token, remainTokens);
|
|
20795
21931
|
this.templates.push(template);
|
|
20796
21932
|
}
|
|
20797
21933
|
throw new Error(`tag ${token.getText()} not closed`);
|
|
@@ -20818,6 +21954,12 @@ class BlockTag extends Tag {
|
|
|
20818
21954
|
? (superBlock, emitter) => renderChild(new BlockDrop(() => renderCurrent(superBlock, emitter)), emitter)
|
|
20819
21955
|
: renderCurrent;
|
|
20820
21956
|
}
|
|
21957
|
+
*children() {
|
|
21958
|
+
return this.templates;
|
|
21959
|
+
}
|
|
21960
|
+
blockScope() {
|
|
21961
|
+
return ['block'];
|
|
21962
|
+
}
|
|
20821
21963
|
}
|
|
20822
21964
|
|
|
20823
21965
|
class RawTag extends Tag {
|
|
@@ -20861,22 +22003,21 @@ class TablerowloopDrop extends ForloopDrop {
|
|
|
20861
22003
|
}
|
|
20862
22004
|
|
|
20863
22005
|
class TablerowTag extends Tag {
|
|
20864
|
-
constructor(tagToken, remainTokens, liquid) {
|
|
22006
|
+
constructor(tagToken, remainTokens, liquid, parser) {
|
|
20865
22007
|
super(tagToken, remainTokens, liquid);
|
|
20866
|
-
const
|
|
20867
|
-
|
|
20868
|
-
tokenizer.
|
|
20869
|
-
const
|
|
20870
|
-
const collectionToken = tokenizer.readValue();
|
|
22008
|
+
const variable = this.tokenizer.readIdentifier();
|
|
22009
|
+
this.tokenizer.skipBlank();
|
|
22010
|
+
const predicate = this.tokenizer.readIdentifier();
|
|
22011
|
+
const collectionToken = this.tokenizer.readValue();
|
|
20871
22012
|
if (predicate.content !== 'in' || !collectionToken) {
|
|
20872
22013
|
throw new Error(`illegal tag: ${tagToken.getText()}`);
|
|
20873
22014
|
}
|
|
20874
22015
|
this.variable = variable.content;
|
|
20875
22016
|
this.collection = collectionToken;
|
|
20876
|
-
this.args = new Hash(tokenizer.
|
|
22017
|
+
this.args = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
|
|
20877
22018
|
this.templates = [];
|
|
20878
22019
|
let p;
|
|
20879
|
-
const stream =
|
|
22020
|
+
const stream = parser.parseStream(remainTokens)
|
|
20880
22021
|
.on('start', () => (p = this.templates))
|
|
20881
22022
|
.on('tag:endtablerow', () => stream.stop())
|
|
20882
22023
|
.on('template', (tpl) => p.push(tpl))
|
|
@@ -20911,28 +22052,56 @@ class TablerowTag extends Tag {
|
|
|
20911
22052
|
emitter.write('</tr>');
|
|
20912
22053
|
ctx.pop();
|
|
20913
22054
|
}
|
|
22055
|
+
*children() {
|
|
22056
|
+
return this.templates;
|
|
22057
|
+
}
|
|
22058
|
+
*arguments() {
|
|
22059
|
+
yield this.collection;
|
|
22060
|
+
for (const v of Object.values(this.args.hash)) {
|
|
22061
|
+
if (isValueToken(v)) {
|
|
22062
|
+
yield v;
|
|
22063
|
+
}
|
|
22064
|
+
}
|
|
22065
|
+
}
|
|
22066
|
+
blockScope() {
|
|
22067
|
+
return [this.variable, 'tablerowloop'];
|
|
22068
|
+
}
|
|
20914
22069
|
}
|
|
20915
22070
|
|
|
20916
22071
|
class UnlessTag extends Tag {
|
|
20917
|
-
constructor(tagToken, remainTokens, liquid) {
|
|
22072
|
+
constructor(tagToken, remainTokens, liquid, parser) {
|
|
20918
22073
|
super(tagToken, remainTokens, liquid);
|
|
20919
22074
|
this.branches = [];
|
|
20920
22075
|
this.elseTemplates = [];
|
|
20921
|
-
let p;
|
|
20922
|
-
|
|
22076
|
+
let p = [];
|
|
22077
|
+
let elseCount = 0;
|
|
22078
|
+
parser.parseStream(remainTokens)
|
|
20923
22079
|
.on('start', () => this.branches.push({
|
|
20924
|
-
value: new Value(tagToken.
|
|
22080
|
+
value: new Value(tagToken.tokenizer.readFilteredValue(), this.liquid),
|
|
20925
22081
|
test: isFalsy,
|
|
20926
22082
|
templates: (p = [])
|
|
20927
22083
|
}))
|
|
20928
|
-
.on('tag:elsif', (token) =>
|
|
20929
|
-
|
|
20930
|
-
|
|
20931
|
-
|
|
20932
|
-
|
|
20933
|
-
.
|
|
22084
|
+
.on('tag:elsif', (token) => {
|
|
22085
|
+
if (elseCount > 0) {
|
|
22086
|
+
p = [];
|
|
22087
|
+
return;
|
|
22088
|
+
}
|
|
22089
|
+
this.branches.push({
|
|
22090
|
+
value: new Value(token.tokenizer.readFilteredValue(), this.liquid),
|
|
22091
|
+
test: isTruthy,
|
|
22092
|
+
templates: (p = [])
|
|
22093
|
+
});
|
|
22094
|
+
})
|
|
22095
|
+
.on('tag:else', () => {
|
|
22096
|
+
elseCount++;
|
|
22097
|
+
p = this.elseTemplates;
|
|
22098
|
+
})
|
|
20934
22099
|
.on('tag:endunless', function () { this.stop(); })
|
|
20935
|
-
.on('template', (tpl) =>
|
|
22100
|
+
.on('template', (tpl) => {
|
|
22101
|
+
if (p !== this.elseTemplates || elseCount === 1) {
|
|
22102
|
+
p.push(tpl);
|
|
22103
|
+
}
|
|
22104
|
+
})
|
|
20936
22105
|
.on('end', () => { throw new Error(`tag ${tagToken.getText()} not closed`); })
|
|
20937
22106
|
.start();
|
|
20938
22107
|
}
|
|
@@ -20947,41 +22116,63 @@ class UnlessTag extends Tag {
|
|
|
20947
22116
|
}
|
|
20948
22117
|
yield r.renderTemplates(this.elseTemplates, ctx, emitter);
|
|
20949
22118
|
}
|
|
22119
|
+
*children() {
|
|
22120
|
+
const children = this.branches.flatMap(b => b.templates);
|
|
22121
|
+
if (this.elseTemplates) {
|
|
22122
|
+
children.push(...this.elseTemplates);
|
|
22123
|
+
}
|
|
22124
|
+
return children;
|
|
22125
|
+
}
|
|
22126
|
+
arguments() {
|
|
22127
|
+
return this.branches.map(b => b.value);
|
|
22128
|
+
}
|
|
20950
22129
|
}
|
|
20951
22130
|
|
|
20952
22131
|
class BreakTag extends Tag {
|
|
20953
|
-
render(ctx,
|
|
20954
|
-
|
|
22132
|
+
render(ctx, _emitter) {
|
|
22133
|
+
ctx.breakCalled = true;
|
|
20955
22134
|
}
|
|
20956
22135
|
}
|
|
20957
22136
|
|
|
20958
22137
|
class ContinueTag extends Tag {
|
|
20959
|
-
render(ctx,
|
|
20960
|
-
|
|
22138
|
+
render(ctx, _emitter) {
|
|
22139
|
+
ctx.continueCalled = true;
|
|
20961
22140
|
}
|
|
20962
22141
|
}
|
|
20963
22142
|
|
|
20964
22143
|
class EchoTag extends Tag {
|
|
20965
22144
|
constructor(token, remainTokens, liquid) {
|
|
20966
22145
|
super(token, remainTokens, liquid);
|
|
20967
|
-
this.
|
|
22146
|
+
this.tokenizer.skipBlank();
|
|
22147
|
+
if (!this.tokenizer.end()) {
|
|
22148
|
+
this.value = new Value(this.tokenizer.readFilteredValue(), this.liquid);
|
|
22149
|
+
}
|
|
20968
22150
|
}
|
|
20969
22151
|
*render(ctx, emitter) {
|
|
22152
|
+
if (!this.value)
|
|
22153
|
+
return;
|
|
20970
22154
|
const val = yield this.value.value(ctx, false);
|
|
20971
22155
|
emitter.write(val);
|
|
20972
22156
|
}
|
|
22157
|
+
*arguments() {
|
|
22158
|
+
if (this.value) {
|
|
22159
|
+
yield this.value;
|
|
22160
|
+
}
|
|
22161
|
+
}
|
|
20973
22162
|
}
|
|
20974
22163
|
|
|
20975
22164
|
class LiquidTag extends Tag {
|
|
20976
|
-
constructor(token, remainTokens, liquid) {
|
|
22165
|
+
constructor(token, remainTokens, liquid, parser) {
|
|
20977
22166
|
super(token, remainTokens, liquid);
|
|
20978
|
-
const
|
|
20979
|
-
|
|
20980
|
-
this.templates = this.liquid.parser.parseTokens(tokens);
|
|
22167
|
+
const tokens = this.tokenizer.readLiquidTagTokens(this.liquid.options);
|
|
22168
|
+
this.templates = parser.parseTokens(tokens);
|
|
20981
22169
|
}
|
|
20982
22170
|
*render(ctx, emitter) {
|
|
20983
22171
|
yield this.liquid.renderer.renderTemplates(this.templates, ctx, emitter);
|
|
20984
22172
|
}
|
|
22173
|
+
*children() {
|
|
22174
|
+
return this.templates;
|
|
22175
|
+
}
|
|
20985
22176
|
}
|
|
20986
22177
|
|
|
20987
22178
|
class InlineCommentTag extends Tag {
|
|
@@ -21024,12 +22215,14 @@ class Liquid {
|
|
|
21024
22215
|
this.filters = {};
|
|
21025
22216
|
this.tags = {};
|
|
21026
22217
|
this.options = normalize(opts);
|
|
22218
|
+
// eslint-disable-next-line deprecation/deprecation
|
|
21027
22219
|
this.parser = new Parser(this);
|
|
21028
22220
|
forOwn(tags, (conf, name) => this.registerTag(name, conf));
|
|
21029
22221
|
forOwn(filters, (handler, name) => this.registerFilter(name, handler));
|
|
21030
22222
|
}
|
|
21031
22223
|
parse(html, filepath) {
|
|
21032
|
-
|
|
22224
|
+
const parser = new Parser(this);
|
|
22225
|
+
return parser.parse(html, filepath);
|
|
21033
22226
|
}
|
|
21034
22227
|
_render(tpl, scope, renderOptions) {
|
|
21035
22228
|
const ctx = scope instanceof Context ? scope : new Context(scope, this.options, renderOptions);
|
|
@@ -21060,21 +22253,21 @@ class Liquid {
|
|
|
21060
22253
|
return toValueSync(this._parseAndRender(html, scope, Object.assign(Object.assign({}, renderOptions), { sync: true })));
|
|
21061
22254
|
}
|
|
21062
22255
|
_parsePartialFile(file, sync, currentFile) {
|
|
21063
|
-
return this.
|
|
22256
|
+
return new Parser(this).parseFile(file, sync, LookupType.Partials, currentFile);
|
|
21064
22257
|
}
|
|
21065
22258
|
_parseLayoutFile(file, sync, currentFile) {
|
|
21066
|
-
return this.
|
|
22259
|
+
return new Parser(this).parseFile(file, sync, LookupType.Layouts, currentFile);
|
|
21067
22260
|
}
|
|
21068
22261
|
_parseFile(file, sync, lookupType, currentFile) {
|
|
21069
|
-
return this.
|
|
22262
|
+
return new Parser(this).parseFile(file, sync, lookupType, currentFile);
|
|
21070
22263
|
}
|
|
21071
22264
|
parseFile(file, lookupType) {
|
|
21072
22265
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21073
|
-
return toPromise(this.
|
|
22266
|
+
return toPromise(new Parser(this).parseFile(file, false, lookupType));
|
|
21074
22267
|
});
|
|
21075
22268
|
}
|
|
21076
22269
|
parseFileSync(file, lookupType) {
|
|
21077
|
-
return toValueSync(this.
|
|
22270
|
+
return toValueSync(new Parser(this).parseFile(file, true, lookupType));
|
|
21078
22271
|
}
|
|
21079
22272
|
*_renderFile(file, ctx, renderFileOptions) {
|
|
21080
22273
|
const templates = (yield this._parseFile(file, renderFileOptions.sync, renderFileOptions.lookupType));
|
|
@@ -21130,6 +22323,94 @@ class Liquid {
|
|
|
21130
22323
|
self.renderFile(filePath, ctx).then(html => callback(null, html), callback);
|
|
21131
22324
|
};
|
|
21132
22325
|
}
|
|
22326
|
+
analyze(template, options = {}) {
|
|
22327
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22328
|
+
return analyze(template, options);
|
|
22329
|
+
});
|
|
22330
|
+
}
|
|
22331
|
+
analyzeSync(template, options = {}) {
|
|
22332
|
+
return analyzeSync(template, options);
|
|
22333
|
+
}
|
|
22334
|
+
parseAndAnalyze(html, filename, options = {}) {
|
|
22335
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22336
|
+
return analyze(this.parse(html, filename), options);
|
|
22337
|
+
});
|
|
22338
|
+
}
|
|
22339
|
+
parseAndAnalyzeSync(html, filename, options = {}) {
|
|
22340
|
+
return analyzeSync(this.parse(html, filename), options);
|
|
22341
|
+
}
|
|
22342
|
+
/** Return an array of all variables without their properties. */
|
|
22343
|
+
variables(template, options = {}) {
|
|
22344
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22345
|
+
const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
|
|
22346
|
+
return Object.keys(analysis.variables);
|
|
22347
|
+
});
|
|
22348
|
+
}
|
|
22349
|
+
/** Return an array of all variables without their properties. */
|
|
22350
|
+
variablesSync(template, options = {}) {
|
|
22351
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
22352
|
+
return Object.keys(analysis.variables);
|
|
22353
|
+
}
|
|
22354
|
+
/** Return an array of all variables including their properties/paths. */
|
|
22355
|
+
fullVariables(template, options = {}) {
|
|
22356
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22357
|
+
const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
|
|
22358
|
+
return Array.from(new Set(Object.values(analysis.variables).flatMap((a) => a.map((v) => String(v)))));
|
|
22359
|
+
});
|
|
22360
|
+
}
|
|
22361
|
+
/** Return an array of all variables including their properties/paths. */
|
|
22362
|
+
fullVariablesSync(template, options = {}) {
|
|
22363
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
22364
|
+
return Array.from(new Set(Object.values(analysis.variables).flatMap((a) => a.map((v) => String(v)))));
|
|
22365
|
+
}
|
|
22366
|
+
/** Return an array of all variables, each as an array of properties/segments. */
|
|
22367
|
+
variableSegments(template, options = {}) {
|
|
22368
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22369
|
+
const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
|
|
22370
|
+
return Array.from(strictUniq(Object.values(analysis.variables).flatMap((a) => a.map((v) => v.toArray()))));
|
|
22371
|
+
});
|
|
22372
|
+
}
|
|
22373
|
+
/** Return an array of all variables, each as an array of properties/segments. */
|
|
22374
|
+
variableSegmentsSync(template, options = {}) {
|
|
22375
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
22376
|
+
return Array.from(strictUniq(Object.values(analysis.variables).flatMap((a) => a.map((v) => v.toArray()))));
|
|
22377
|
+
}
|
|
22378
|
+
/** Return an array of all expected context variables without their properties. */
|
|
22379
|
+
globalVariables(template, options = {}) {
|
|
22380
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22381
|
+
const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
|
|
22382
|
+
return Object.keys(analysis.globals);
|
|
22383
|
+
});
|
|
22384
|
+
}
|
|
22385
|
+
/** Return an array of all expected context variables without their properties. */
|
|
22386
|
+
globalVariablesSync(template, options = {}) {
|
|
22387
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
22388
|
+
return Object.keys(analysis.globals);
|
|
22389
|
+
}
|
|
22390
|
+
/** Return an array of all expected context variables including their properties/paths. */
|
|
22391
|
+
globalFullVariables(template, options = {}) {
|
|
22392
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22393
|
+
const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
|
|
22394
|
+
return Array.from(new Set(Object.values(analysis.globals).flatMap((a) => a.map((v) => String(v)))));
|
|
22395
|
+
});
|
|
22396
|
+
}
|
|
22397
|
+
/** Return an array of all expected context variables including their properties/paths. */
|
|
22398
|
+
globalFullVariablesSync(template, options = {}) {
|
|
22399
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
22400
|
+
return Array.from(new Set(Object.values(analysis.globals).flatMap((a) => a.map((v) => String(v)))));
|
|
22401
|
+
}
|
|
22402
|
+
/** Return an array of all expected context variables, each as an array of properties/segments. */
|
|
22403
|
+
globalVariableSegments(template, options = {}) {
|
|
22404
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22405
|
+
const analysis = yield analyze(isString(template) ? this.parse(template) : template, options);
|
|
22406
|
+
return Array.from(strictUniq(Object.values(analysis.globals).flatMap((a) => a.map((v) => v.toArray()))));
|
|
22407
|
+
});
|
|
22408
|
+
}
|
|
22409
|
+
/** Return an array of all expected context variables, each as an array of properties/segments. */
|
|
22410
|
+
globalVariableSegmentsSync(template, options = {}) {
|
|
22411
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
22412
|
+
return Array.from(strictUniq(Object.values(analysis.globals).flatMap((a) => a.map((v) => v.toArray()))));
|
|
22413
|
+
}
|
|
21133
22414
|
}
|
|
21134
22415
|
|
|
21135
22416
|
const engine = new Liquid();
|
|
@@ -21183,6 +22464,14 @@ var e4 = defineHook(({}, { services, getSchema, logger, env }) => {
|
|
|
21183
22464
|
await addField("format", "string");
|
|
21184
22465
|
if (fields.orientation == null)
|
|
21185
22466
|
await addField("orientation", "string");
|
|
22467
|
+
if (fields.input_type == null)
|
|
22468
|
+
await addField("input_type", "string");
|
|
22469
|
+
if (fields.input_flow == null)
|
|
22470
|
+
await addField("input_flow", "string");
|
|
22471
|
+
if (fields.input_flow_body == null)
|
|
22472
|
+
await addField("input_flow_body", "text");
|
|
22473
|
+
if (fields.input_fixed == null)
|
|
22474
|
+
await addField("input_fixed", "text");
|
|
21186
22475
|
if (((_a = schema.collections.directus_settings) == null ? void 0 : _a.fields.TTA_KEY) == null) {
|
|
21187
22476
|
await addField(
|
|
21188
22477
|
"TTA_KEY",
|
|
@@ -21297,8 +22586,9 @@ var e4 = defineHook(({}, { services, getSchema, logger, env }) => {
|
|
|
21297
22586
|
});
|
|
21298
22587
|
} catch (error) {
|
|
21299
22588
|
logger.warn(
|
|
21300
|
-
"[TTA] Error while creating '" + name + "' in the collection " + collection
|
|
22589
|
+
"[TTA] Error while creating '" + name + "' in the collection " + collection + ": "
|
|
21301
22590
|
);
|
|
22591
|
+
console.error(error);
|
|
21302
22592
|
}
|
|
21303
22593
|
}
|
|
21304
22594
|
async function handleRapidAPIError(error) {
|