@skeptools/skep-organization-project 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +29 -4
- package/API.md +63 -1
- package/lib/skep-organization-project.js +1 -1
- package/node_modules/liquidjs/README.md +15 -10
- package/node_modules/liquidjs/dist/context/context.d.ts +6 -3
- package/node_modules/liquidjs/dist/drop/blank-drop.d.ts +1 -0
- package/node_modules/liquidjs/dist/drop/empty-drop.d.ts +1 -0
- package/node_modules/liquidjs/dist/index.d.ts +2 -2
- package/node_modules/liquidjs/dist/liquid-options.d.ts +2 -0
- package/node_modules/liquidjs/dist/liquid.browser.min.js +1 -1
- package/node_modules/liquidjs/dist/liquid.browser.min.js.map +1 -1
- package/node_modules/liquidjs/dist/liquid.browser.mjs +712 -45
- package/node_modules/liquidjs/dist/liquid.browser.umd.js +1573 -215
- package/node_modules/liquidjs/dist/liquid.browser.umd.js.map +1 -1
- package/node_modules/liquidjs/dist/liquid.d.ts +29 -1
- package/node_modules/liquidjs/dist/liquid.node.js +699 -45
- package/node_modules/liquidjs/dist/liquid.node.mjs +712 -45
- package/node_modules/liquidjs/dist/render/expression.d.ts +1 -1
- package/node_modules/liquidjs/dist/render/operator.d.ts +1 -0
- package/node_modules/liquidjs/dist/tags/assign.d.ts +5 -0
- package/node_modules/liquidjs/dist/tags/block.d.ts +2 -0
- package/node_modules/liquidjs/dist/tags/break.d.ts +1 -1
- package/node_modules/liquidjs/dist/tags/capture.d.ts +5 -1
- package/node_modules/liquidjs/dist/tags/case.d.ts +3 -0
- package/node_modules/liquidjs/dist/tags/continue.d.ts +1 -1
- package/node_modules/liquidjs/dist/tags/cycle.d.ts +2 -0
- package/node_modules/liquidjs/dist/tags/decrement.d.ts +3 -0
- package/node_modules/liquidjs/dist/tags/echo.d.ts +2 -0
- package/node_modules/liquidjs/dist/tags/for.d.ts +4 -0
- package/node_modules/liquidjs/dist/tags/if.d.ts +3 -0
- package/node_modules/liquidjs/dist/tags/include.d.ts +5 -1
- package/node_modules/liquidjs/dist/tags/increment.d.ts +3 -0
- package/node_modules/liquidjs/dist/tags/layout.d.ts +4 -0
- package/node_modules/liquidjs/dist/tags/liquid.d.ts +1 -0
- package/node_modules/liquidjs/dist/tags/render.d.ts +4 -0
- package/node_modules/liquidjs/dist/tags/tablerow.d.ts +4 -0
- package/node_modules/liquidjs/dist/tags/unless.d.ts +3 -0
- package/node_modules/liquidjs/dist/template/analysis.d.ts +85 -0
- package/node_modules/liquidjs/dist/template/analysis.spec.d.ts +1 -0
- package/node_modules/liquidjs/dist/template/hash.d.ts +2 -1
- package/node_modules/liquidjs/dist/template/index.d.ts +1 -0
- package/node_modules/liquidjs/dist/template/output.d.ts +2 -1
- package/node_modules/liquidjs/dist/template/template.d.ts +29 -0
- package/node_modules/liquidjs/dist/tokens/liquid-tag-token.d.ts +1 -1
- package/node_modules/liquidjs/dist/util/type-guards.d.ts +2 -1
- package/node_modules/liquidjs/dist/util/underscore.d.ts +3 -0
- package/node_modules/liquidjs/package.json +2 -1
- package/package.json +4 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* liquidjs@10.
|
|
3
|
-
* (c) 2016-
|
|
2
|
+
* liquidjs@10.20.1, https://github.com/harttle/liquidjs
|
|
3
|
+
* (c) 2016-2025 harttle
|
|
4
4
|
* Released under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
@@ -128,6 +128,9 @@ function isArray(value) {
|
|
|
128
128
|
// be compatible with IE 8
|
|
129
129
|
return toString$1.call(value) === '[object Array]';
|
|
130
130
|
}
|
|
131
|
+
function isArrayLike(value) {
|
|
132
|
+
return value && isNumber(value.length);
|
|
133
|
+
}
|
|
131
134
|
function isIterable(value) {
|
|
132
135
|
return isObject(value) && Symbol.iterator in value;
|
|
133
136
|
}
|
|
@@ -213,6 +216,17 @@ function argumentsToValue(fn) {
|
|
|
213
216
|
}
|
|
214
217
|
function escapeRegExp(text) {
|
|
215
218
|
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
|
|
219
|
+
}
|
|
220
|
+
/** Return an array containing unique elements from _array_. Works with nested arrays and objects. */
|
|
221
|
+
function* strictUniq(array) {
|
|
222
|
+
const seen = new Set();
|
|
223
|
+
for (const element of array) {
|
|
224
|
+
const key = JSON.stringify(element);
|
|
225
|
+
if (!seen.has(key)) {
|
|
226
|
+
seen.add(key);
|
|
227
|
+
yield element;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
216
230
|
}
|
|
217
231
|
|
|
218
232
|
/**
|
|
@@ -413,6 +427,9 @@ class EmptyDrop extends Drop {
|
|
|
413
427
|
valueOf() {
|
|
414
428
|
return '';
|
|
415
429
|
}
|
|
430
|
+
static is(value) {
|
|
431
|
+
return value instanceof EmptyDrop;
|
|
432
|
+
}
|
|
416
433
|
}
|
|
417
434
|
|
|
418
435
|
class BlankDrop extends EmptyDrop {
|
|
@@ -425,6 +442,9 @@ class BlankDrop extends EmptyDrop {
|
|
|
425
442
|
return /^\s*$/.test(value);
|
|
426
443
|
return super.equals(value);
|
|
427
444
|
}
|
|
445
|
+
static is(value) {
|
|
446
|
+
return value instanceof BlankDrop;
|
|
447
|
+
}
|
|
428
448
|
}
|
|
429
449
|
|
|
430
450
|
class ForloopDrop extends Drop {
|
|
@@ -711,7 +731,11 @@ function getDateTimeFormat() {
|
|
|
711
731
|
|
|
712
732
|
// one minute in milliseconds
|
|
713
733
|
const OneMinute = 60000;
|
|
714
|
-
|
|
734
|
+
/**
|
|
735
|
+
* Need support both ISO8601 and RFC2822 as in major browsers & NodeJS
|
|
736
|
+
* RFC2822: https://datatracker.ietf.org/doc/html/rfc2822#section-3.3
|
|
737
|
+
*/
|
|
738
|
+
const TIMEZONE_PATTERN = /([zZ]|([+-])(\d{2}):?(\d{2}))$/;
|
|
715
739
|
const monthNames = [
|
|
716
740
|
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
|
|
717
741
|
'September', 'October', 'November', 'December'
|
|
@@ -824,7 +848,7 @@ class LiquidDate {
|
|
|
824
848
|
* Given that a template is expected to be parsed fewer times than rendered.
|
|
825
849
|
*/
|
|
826
850
|
static createDateFixedToTimezone(dateString, locale) {
|
|
827
|
-
const m = dateString.match(
|
|
851
|
+
const m = dateString.match(TIMEZONE_PATTERN);
|
|
828
852
|
// representing a UTC timestamp
|
|
829
853
|
if (m && m[1] === 'Z') {
|
|
830
854
|
return new LiquidDate(+new Date(dateString), locale, 0);
|
|
@@ -1110,7 +1134,9 @@ class LiquidTagToken extends DelimitedToken {
|
|
|
1110
1134
|
this.name = this.tokenizer.readTagName();
|
|
1111
1135
|
this.tokenizer.assert(this.name, 'illegal liquid tag syntax');
|
|
1112
1136
|
this.tokenizer.skipBlank();
|
|
1113
|
-
|
|
1137
|
+
}
|
|
1138
|
+
get args() {
|
|
1139
|
+
return this.tokenizer.input.slice(this.tokenizer.p, this.contentRange[1]);
|
|
1114
1140
|
}
|
|
1115
1141
|
}
|
|
1116
1142
|
|
|
@@ -1203,7 +1229,7 @@ class Render {
|
|
|
1203
1229
|
const html = yield tpl.render(ctx, emitter);
|
|
1204
1230
|
// if not, it'll return an `html`, write to the emitter for it
|
|
1205
1231
|
html && emitter.write(html);
|
|
1206
|
-
if (
|
|
1232
|
+
if (ctx.breakCalled || ctx.continueCalled)
|
|
1207
1233
|
break;
|
|
1208
1234
|
}
|
|
1209
1235
|
catch (e) {
|
|
@@ -1287,6 +1313,7 @@ function evalQuotedToken(token) {
|
|
|
1287
1313
|
function* evalRangeToken(token, ctx) {
|
|
1288
1314
|
const low = yield evalToken(token.lhs, ctx);
|
|
1289
1315
|
const high = yield evalToken(token.rhs, ctx);
|
|
1316
|
+
ctx.memoryLimit.use(high - low + 1);
|
|
1290
1317
|
return range(+low, +high + 1);
|
|
1291
1318
|
}
|
|
1292
1319
|
function* toPostfix(tokens) {
|
|
@@ -1378,6 +1405,9 @@ function arrayEquals(lhs, rhs) {
|
|
|
1378
1405
|
if (lhs.length !== rhs.length)
|
|
1379
1406
|
return false;
|
|
1380
1407
|
return !lhs.some((value, i) => !equals(value, rhs[i]));
|
|
1408
|
+
}
|
|
1409
|
+
function arrayIncludes(arr, item) {
|
|
1410
|
+
return arr.some(value => equals(value, item));
|
|
1381
1411
|
}
|
|
1382
1412
|
|
|
1383
1413
|
class Node {
|
|
@@ -2264,9 +2294,9 @@ class Tag extends TemplateImpl {
|
|
|
2264
2294
|
* hash['reversed'] === undefined
|
|
2265
2295
|
*/
|
|
2266
2296
|
class Hash {
|
|
2267
|
-
constructor(
|
|
2297
|
+
constructor(input, jekyllStyle) {
|
|
2268
2298
|
this.hash = {};
|
|
2269
|
-
const tokenizer = new Tokenizer(
|
|
2299
|
+
const tokenizer = input instanceof Tokenizer ? input : new Tokenizer(input, {});
|
|
2270
2300
|
for (const hash of tokenizer.readHashes(jekyllStyle)) {
|
|
2271
2301
|
this.hash[hash.name.content] = hash.value;
|
|
2272
2302
|
}
|
|
@@ -2365,6 +2395,9 @@ class Output extends TemplateImpl {
|
|
|
2365
2395
|
const val = yield this.value.value(ctx, false);
|
|
2366
2396
|
emitter.write(val);
|
|
2367
2397
|
}
|
|
2398
|
+
*arguments() {
|
|
2399
|
+
yield this.value;
|
|
2400
|
+
}
|
|
2368
2401
|
}
|
|
2369
2402
|
|
|
2370
2403
|
class HTML extends TemplateImpl {
|
|
@@ -2377,6 +2410,335 @@ class HTML extends TemplateImpl {
|
|
|
2377
2410
|
}
|
|
2378
2411
|
}
|
|
2379
2412
|
|
|
2413
|
+
/**
|
|
2414
|
+
* A variable's segments and location, which can be coerced to a string.
|
|
2415
|
+
*/
|
|
2416
|
+
class Variable {
|
|
2417
|
+
constructor(segments, location) {
|
|
2418
|
+
this.segments = segments;
|
|
2419
|
+
this.location = location;
|
|
2420
|
+
}
|
|
2421
|
+
toString() {
|
|
2422
|
+
return segmentsString(this.segments, true);
|
|
2423
|
+
}
|
|
2424
|
+
/** Return this variable's segments as an array, possibly with nested arrays for nested paths. */
|
|
2425
|
+
toArray() {
|
|
2426
|
+
function* _visit(...segments) {
|
|
2427
|
+
for (const segment of segments) {
|
|
2428
|
+
if (segment instanceof Variable) {
|
|
2429
|
+
yield Array.from(_visit(...segment.segments));
|
|
2430
|
+
}
|
|
2431
|
+
else {
|
|
2432
|
+
yield segment;
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
return Array.from(_visit(...this.segments));
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
/**
|
|
2440
|
+
* Group variables by the string representation of their root segment.
|
|
2441
|
+
*/
|
|
2442
|
+
class VariableMap {
|
|
2443
|
+
constructor() {
|
|
2444
|
+
this.map = new Map();
|
|
2445
|
+
}
|
|
2446
|
+
get(key) {
|
|
2447
|
+
const k = segmentsString([key.segments[0]]);
|
|
2448
|
+
if (!this.map.has(k)) {
|
|
2449
|
+
this.map.set(k, []);
|
|
2450
|
+
}
|
|
2451
|
+
return this.map.get(k);
|
|
2452
|
+
}
|
|
2453
|
+
has(key) {
|
|
2454
|
+
return this.map.has(segmentsString([key.segments[0]]));
|
|
2455
|
+
}
|
|
2456
|
+
push(variable) {
|
|
2457
|
+
this.get(variable).push(variable);
|
|
2458
|
+
}
|
|
2459
|
+
asObject() {
|
|
2460
|
+
return Object.fromEntries(this.map);
|
|
2461
|
+
}
|
|
2462
|
+
}
|
|
2463
|
+
const defaultStaticAnalysisOptions = {
|
|
2464
|
+
partials: true
|
|
2465
|
+
};
|
|
2466
|
+
function* _analyze(templates, partials, sync) {
|
|
2467
|
+
const variables = new VariableMap();
|
|
2468
|
+
const globals = new VariableMap();
|
|
2469
|
+
const locals = new VariableMap();
|
|
2470
|
+
const rootScope = new DummyScope(new Set());
|
|
2471
|
+
// Names of partial templates that we've already analyzed.
|
|
2472
|
+
const seen = new Set();
|
|
2473
|
+
function updateVariables(variable, scope) {
|
|
2474
|
+
variables.push(variable);
|
|
2475
|
+
const aliased = scope.alias(variable);
|
|
2476
|
+
if (aliased !== undefined) {
|
|
2477
|
+
const root = aliased.segments[0];
|
|
2478
|
+
// TODO: What if a a template renders a rendered template? Do we need scope.parent?
|
|
2479
|
+
if (isString(root) && !rootScope.has(root)) {
|
|
2480
|
+
globals.push(aliased);
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
else {
|
|
2484
|
+
const root = variable.segments[0];
|
|
2485
|
+
if (isString(root) && !scope.has(root)) {
|
|
2486
|
+
globals.push(variable);
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
// Recurse for nested Variables
|
|
2490
|
+
for (const segment of variable.segments) {
|
|
2491
|
+
if (segment instanceof Variable) {
|
|
2492
|
+
updateVariables(segment, scope);
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
function* visit(template, scope) {
|
|
2497
|
+
if (template.arguments) {
|
|
2498
|
+
for (const arg of template.arguments()) {
|
|
2499
|
+
for (const variable of extractVariables(arg)) {
|
|
2500
|
+
updateVariables(variable, scope);
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
if (template.localScope) {
|
|
2505
|
+
for (const ident of template.localScope()) {
|
|
2506
|
+
scope.add(ident.content);
|
|
2507
|
+
scope.deleteAlias(ident.content);
|
|
2508
|
+
const [row, col] = ident.getPosition();
|
|
2509
|
+
locals.push(new Variable([ident.content], { row, col, file: ident.file }));
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
if (template.children) {
|
|
2513
|
+
if (template.partialScope) {
|
|
2514
|
+
const partial = template.partialScope();
|
|
2515
|
+
if (partial === undefined) {
|
|
2516
|
+
// Layouts, for example, can have children that are not partials.
|
|
2517
|
+
for (const child of (yield template.children(partials, sync))) {
|
|
2518
|
+
yield visit(child, scope);
|
|
2519
|
+
}
|
|
2520
|
+
return;
|
|
2521
|
+
}
|
|
2522
|
+
if (seen.has(partial.name))
|
|
2523
|
+
return;
|
|
2524
|
+
const partialScopeNames = new Set();
|
|
2525
|
+
const partialScope = partial.isolated
|
|
2526
|
+
? new DummyScope(partialScopeNames)
|
|
2527
|
+
: scope.push(partialScopeNames);
|
|
2528
|
+
for (const name of partial.scope) {
|
|
2529
|
+
if (isString(name)) {
|
|
2530
|
+
partialScopeNames.add(name);
|
|
2531
|
+
}
|
|
2532
|
+
else {
|
|
2533
|
+
const [alias, argument] = name;
|
|
2534
|
+
partialScopeNames.add(alias);
|
|
2535
|
+
const variables = Array.from(extractVariables(argument));
|
|
2536
|
+
if (variables.length) {
|
|
2537
|
+
partialScope.setAlias(alias, variables[0].segments);
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
for (const child of (yield template.children(partials, sync))) {
|
|
2542
|
+
yield visit(child, partialScope);
|
|
2543
|
+
seen.add(partial.name);
|
|
2544
|
+
}
|
|
2545
|
+
partialScope.pop();
|
|
2546
|
+
}
|
|
2547
|
+
else {
|
|
2548
|
+
if (template.blockScope) {
|
|
2549
|
+
scope.push(new Set(template.blockScope()));
|
|
2550
|
+
}
|
|
2551
|
+
for (const child of (yield template.children(partials, sync))) {
|
|
2552
|
+
yield visit(child, scope);
|
|
2553
|
+
}
|
|
2554
|
+
if (template.blockScope) {
|
|
2555
|
+
scope.pop();
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
for (const template of templates) {
|
|
2561
|
+
yield visit(template, rootScope);
|
|
2562
|
+
}
|
|
2563
|
+
return {
|
|
2564
|
+
variables: variables.asObject(),
|
|
2565
|
+
globals: globals.asObject(),
|
|
2566
|
+
locals: locals.asObject()
|
|
2567
|
+
};
|
|
2568
|
+
}
|
|
2569
|
+
/**
|
|
2570
|
+
* Statically analyze a template and report variable usage.
|
|
2571
|
+
*/
|
|
2572
|
+
function analyze(template, options = {}) {
|
|
2573
|
+
const opts = { ...defaultStaticAnalysisOptions, ...options };
|
|
2574
|
+
return toPromise(_analyze(template, opts.partials, false));
|
|
2575
|
+
}
|
|
2576
|
+
/**
|
|
2577
|
+
* Statically analyze a template and report variable usage.
|
|
2578
|
+
*/
|
|
2579
|
+
function analyzeSync(template, options = {}) {
|
|
2580
|
+
const opts = { ...defaultStaticAnalysisOptions, ...options };
|
|
2581
|
+
return toValueSync(_analyze(template, opts.partials, true));
|
|
2582
|
+
}
|
|
2583
|
+
/**
|
|
2584
|
+
* A stack to manage scopes while traversing templates during static analysis.
|
|
2585
|
+
*/
|
|
2586
|
+
class DummyScope {
|
|
2587
|
+
constructor(globals) {
|
|
2588
|
+
this.stack = [{ names: globals, aliases: new Map() }];
|
|
2589
|
+
}
|
|
2590
|
+
/** Return true if `name` is in scope. */
|
|
2591
|
+
has(name) {
|
|
2592
|
+
for (const scope of this.stack) {
|
|
2593
|
+
if (scope.names.has(name)) {
|
|
2594
|
+
return true;
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
return false;
|
|
2598
|
+
}
|
|
2599
|
+
push(scope) {
|
|
2600
|
+
this.stack.push({ names: scope, aliases: new Map() });
|
|
2601
|
+
return this;
|
|
2602
|
+
}
|
|
2603
|
+
pop() {
|
|
2604
|
+
return this.stack.pop()?.names;
|
|
2605
|
+
}
|
|
2606
|
+
// Add a name to the template scope.
|
|
2607
|
+
add(name) {
|
|
2608
|
+
this.stack[0].names.add(name);
|
|
2609
|
+
}
|
|
2610
|
+
/** Return the variable that `variable` aliases, or `variable` if it doesn't alias anything. */
|
|
2611
|
+
alias(variable) {
|
|
2612
|
+
const root = variable.segments[0];
|
|
2613
|
+
if (!isString(root))
|
|
2614
|
+
return undefined;
|
|
2615
|
+
const alias = this.getAlias(root);
|
|
2616
|
+
if (alias === undefined)
|
|
2617
|
+
return undefined;
|
|
2618
|
+
return new Variable([...alias, ...variable.segments.slice(1)], variable.location);
|
|
2619
|
+
}
|
|
2620
|
+
// TODO: `from` could be a path with multiple segments, like `include.x`.
|
|
2621
|
+
setAlias(from, to) {
|
|
2622
|
+
this.stack[this.stack.length - 1].aliases.set(from, to);
|
|
2623
|
+
}
|
|
2624
|
+
deleteAlias(name) {
|
|
2625
|
+
this.stack[this.stack.length - 1].aliases.delete(name);
|
|
2626
|
+
}
|
|
2627
|
+
getAlias(name) {
|
|
2628
|
+
for (const scope of this.stack) {
|
|
2629
|
+
if (scope.aliases.has(name)) {
|
|
2630
|
+
return scope.aliases.get(name);
|
|
2631
|
+
}
|
|
2632
|
+
// If a scope has defined `name`, then it masks aliases in parent scopes.
|
|
2633
|
+
if (scope.names.has(name)) {
|
|
2634
|
+
return undefined;
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
return undefined;
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
function* extractVariables(value) {
|
|
2641
|
+
if (isValueToken(value)) {
|
|
2642
|
+
yield* extractValueTokenVariables(value);
|
|
2643
|
+
}
|
|
2644
|
+
else if (value instanceof Value) {
|
|
2645
|
+
yield* extractFilteredValueVariables(value);
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
function* extractFilteredValueVariables(value) {
|
|
2649
|
+
for (const token of value.initial.postfix) {
|
|
2650
|
+
if (isValueToken(token)) {
|
|
2651
|
+
yield* extractValueTokenVariables(token);
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
for (const filter of value.filters) {
|
|
2655
|
+
for (const arg of filter.args) {
|
|
2656
|
+
if (isKeyValuePair(arg) && arg[1]) {
|
|
2657
|
+
yield* extractValueTokenVariables(arg[1]);
|
|
2658
|
+
}
|
|
2659
|
+
else if (isValueToken(arg)) {
|
|
2660
|
+
yield* extractValueTokenVariables(arg);
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
function* extractValueTokenVariables(token) {
|
|
2666
|
+
if (isRangeToken(token)) {
|
|
2667
|
+
yield* extractValueTokenVariables(token.lhs);
|
|
2668
|
+
yield* extractValueTokenVariables(token.rhs);
|
|
2669
|
+
}
|
|
2670
|
+
else if (isPropertyAccessToken(token)) {
|
|
2671
|
+
yield extractPropertyAccessVariable(token);
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
function extractPropertyAccessVariable(token) {
|
|
2675
|
+
const segments = [];
|
|
2676
|
+
// token is not guaranteed to have `file` set. We'll try to get it from a prop if not.
|
|
2677
|
+
let file = token.file;
|
|
2678
|
+
// Here we're flattening the first segment of a path if it is a nested path.
|
|
2679
|
+
const root = token.props[0];
|
|
2680
|
+
file = file || root.file;
|
|
2681
|
+
if (isQuotedToken(root) || isNumberToken(root) || isWordToken(root)) {
|
|
2682
|
+
segments.push(root.content);
|
|
2683
|
+
}
|
|
2684
|
+
else if (isPropertyAccessToken(root)) {
|
|
2685
|
+
// Flatten paths that start with a nested path.
|
|
2686
|
+
segments.push(...extractPropertyAccessVariable(root).segments);
|
|
2687
|
+
}
|
|
2688
|
+
for (const prop of token.props.slice(1)) {
|
|
2689
|
+
file = file || prop.file;
|
|
2690
|
+
if (isQuotedToken(prop) || isNumberToken(prop) || isWordToken(prop)) {
|
|
2691
|
+
segments.push(prop.content);
|
|
2692
|
+
}
|
|
2693
|
+
else if (isPropertyAccessToken(prop)) {
|
|
2694
|
+
segments.push(extractPropertyAccessVariable(prop));
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
const [row, col] = token.getPosition();
|
|
2698
|
+
return new Variable(segments, {
|
|
2699
|
+
row,
|
|
2700
|
+
col,
|
|
2701
|
+
file
|
|
2702
|
+
});
|
|
2703
|
+
}
|
|
2704
|
+
// This is used to detect segments that can be represented with dot notation
|
|
2705
|
+
// when creating a string representation of VariableSegments.
|
|
2706
|
+
const RE_PROPERTY = /^[\u0080-\uFFFFa-zA-Z_][\u0080-\uFFFFa-zA-Z0-9_-]*$/;
|
|
2707
|
+
/**
|
|
2708
|
+
* Return a string representation of segments using dot notation where possible.
|
|
2709
|
+
* @param segments - The property names and array indices that make up a path to a variable.
|
|
2710
|
+
* @param bracketedRoot - If false (the default), don't surround the root segment with square brackets.
|
|
2711
|
+
*/
|
|
2712
|
+
function segmentsString(segments, bracketedRoot = false) {
|
|
2713
|
+
const buf = [];
|
|
2714
|
+
const root = segments[0];
|
|
2715
|
+
if (isString(root)) {
|
|
2716
|
+
if (!bracketedRoot || root.match(RE_PROPERTY)) {
|
|
2717
|
+
buf.push(`${root}`);
|
|
2718
|
+
}
|
|
2719
|
+
else {
|
|
2720
|
+
buf.push(`['${root}']`);
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
for (const segment of segments.slice(1)) {
|
|
2724
|
+
if (segment instanceof Variable) {
|
|
2725
|
+
buf.push(`[${segmentsString(segment.segments)}]`);
|
|
2726
|
+
}
|
|
2727
|
+
else if (isString(segment)) {
|
|
2728
|
+
if (segment.match(RE_PROPERTY)) {
|
|
2729
|
+
buf.push(`.${segment}`);
|
|
2730
|
+
}
|
|
2731
|
+
else {
|
|
2732
|
+
buf.push(`['${segment}']`);
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
else {
|
|
2736
|
+
buf.push(`[${segment}]`);
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
return buf.join('');
|
|
2740
|
+
}
|
|
2741
|
+
|
|
2380
2742
|
var LookupType;
|
|
2381
2743
|
(function (LookupType) {
|
|
2382
2744
|
LookupType["Partials"] = "partials";
|
|
@@ -2575,6 +2937,10 @@ function isWordToken(val) {
|
|
|
2575
2937
|
function isRangeToken(val) {
|
|
2576
2938
|
return getKind(val) === exports.TokenKind.Range;
|
|
2577
2939
|
}
|
|
2940
|
+
function isValueToken(val) {
|
|
2941
|
+
// valueTokenBitMask = TokenKind.Number | TokenKind.Literal | TokenKind.Quoted | TokenKind.PropertyAccess | TokenKind.Range
|
|
2942
|
+
return (getKind(val) & 1667) > 0;
|
|
2943
|
+
}
|
|
2578
2944
|
function getKind(val) {
|
|
2579
2945
|
return val ? val.kind : -1;
|
|
2580
2946
|
}
|
|
@@ -2591,7 +2957,8 @@ var typeGuards = /*#__PURE__*/Object.freeze({
|
|
|
2591
2957
|
isNumberToken: isNumberToken,
|
|
2592
2958
|
isPropertyAccessToken: isPropertyAccessToken,
|
|
2593
2959
|
isWordToken: isWordToken,
|
|
2594
|
-
isRangeToken: isRangeToken
|
|
2960
|
+
isRangeToken: isRangeToken,
|
|
2961
|
+
isValueToken: isValueToken
|
|
2595
2962
|
});
|
|
2596
2963
|
|
|
2597
2964
|
/******************************************************************************
|
|
@@ -2628,6 +2995,8 @@ class Context {
|
|
|
2628
2995
|
*/
|
|
2629
2996
|
this.scopes = [{}];
|
|
2630
2997
|
this.registers = {};
|
|
2998
|
+
this.breakCalled = false;
|
|
2999
|
+
this.continueCalled = false;
|
|
2631
3000
|
this.sync = !!renderOptions.sync;
|
|
2632
3001
|
this.opts = opts;
|
|
2633
3002
|
this.globals = renderOptions.globals ?? opts.globals;
|
|
@@ -2663,7 +3032,7 @@ class Context {
|
|
|
2663
3032
|
return toValueSync(this._get(paths));
|
|
2664
3033
|
}
|
|
2665
3034
|
*_get(paths) {
|
|
2666
|
-
const scope = this.findScope(paths[0]);
|
|
3035
|
+
const scope = this.findScope(paths[0]); // first prop should always be a string
|
|
2667
3036
|
return yield this._getFromScope(scope, paths);
|
|
2668
3037
|
}
|
|
2669
3038
|
/**
|
|
@@ -2715,6 +3084,7 @@ class Context {
|
|
|
2715
3084
|
}
|
|
2716
3085
|
function readProperty(obj, key, ownPropertyOnly) {
|
|
2717
3086
|
obj = toLiquid(obj);
|
|
3087
|
+
key = toValue(key);
|
|
2718
3088
|
if (isNil(obj))
|
|
2719
3089
|
return obj;
|
|
2720
3090
|
if (isArray(obj) && key < 0)
|
|
@@ -2862,8 +3232,8 @@ const join = argumentsToValue(function (v, arg) {
|
|
|
2862
3232
|
this.context.memoryLimit.use(complexity);
|
|
2863
3233
|
return array.join(sep);
|
|
2864
3234
|
});
|
|
2865
|
-
const last$1 = argumentsToValue((v) =>
|
|
2866
|
-
const first = argumentsToValue((v) =>
|
|
3235
|
+
const last$1 = argumentsToValue((v) => isArrayLike(v) ? last(v) : '');
|
|
3236
|
+
const first = argumentsToValue((v) => isArrayLike(v) ? v[0] : '');
|
|
2867
3237
|
const reverse = argumentsToValue(function (v) {
|
|
2868
3238
|
const array = toArray(v);
|
|
2869
3239
|
this.context.memoryLimit.use(array.length);
|
|
@@ -2964,10 +3334,13 @@ function* where(arr, property, expected) {
|
|
|
2964
3334
|
for (const item of arr) {
|
|
2965
3335
|
values.push(yield evalToken(token, this.context.spawn(item)));
|
|
2966
3336
|
}
|
|
3337
|
+
const matcher = this.context.opts.jekyllWhere
|
|
3338
|
+
? (v) => EmptyDrop.is(expected) ? equals(v, expected) : (isArray(v) ? arrayIncludes(v, expected) : equals(v, expected))
|
|
3339
|
+
: (v) => equals(v, expected);
|
|
2967
3340
|
return arr.filter((_, i) => {
|
|
2968
3341
|
if (expected === undefined)
|
|
2969
3342
|
return isTruthy(values[i], this.context);
|
|
2970
|
-
return
|
|
3343
|
+
return matcher(values[i]);
|
|
2971
3344
|
});
|
|
2972
3345
|
}
|
|
2973
3346
|
function* where_exp(arr, itemName, exp) {
|
|
@@ -2984,7 +3357,7 @@ function* where_exp(arr, itemName, exp) {
|
|
|
2984
3357
|
}
|
|
2985
3358
|
function* group_by(arr, property) {
|
|
2986
3359
|
const map = new Map();
|
|
2987
|
-
arr =
|
|
3360
|
+
arr = toEnumerable(arr);
|
|
2988
3361
|
const token = new Tokenizer(stringify(property)).readScopeValue();
|
|
2989
3362
|
this.context.memoryLimit.use(arr.length);
|
|
2990
3363
|
for (const item of arr) {
|
|
@@ -2998,7 +3371,7 @@ function* group_by(arr, property) {
|
|
|
2998
3371
|
function* group_by_exp(arr, itemName, exp) {
|
|
2999
3372
|
const map = new Map();
|
|
3000
3373
|
const keyTemplate = new Value(stringify(exp), this.liquid);
|
|
3001
|
-
arr =
|
|
3374
|
+
arr = toEnumerable(arr);
|
|
3002
3375
|
this.context.memoryLimit.use(arr.length);
|
|
3003
3376
|
for (const item of arr) {
|
|
3004
3377
|
const key = yield keyTemplate.value(this.context.spawn({ [itemName]: item }));
|
|
@@ -3358,7 +3731,8 @@ const filters = {
|
|
|
3358
3731
|
class AssignTag extends Tag {
|
|
3359
3732
|
constructor(token, remainTokens, liquid) {
|
|
3360
3733
|
super(token, remainTokens, liquid);
|
|
3361
|
-
this.
|
|
3734
|
+
this.identifier = this.tokenizer.readIdentifier();
|
|
3735
|
+
this.key = this.identifier.content;
|
|
3362
3736
|
this.tokenizer.assert(this.key, 'expected variable name');
|
|
3363
3737
|
this.tokenizer.skipBlank();
|
|
3364
3738
|
this.tokenizer.assert(this.tokenizer.peek() === '=', 'expected "="');
|
|
@@ -3368,6 +3742,12 @@ class AssignTag extends Tag {
|
|
|
3368
3742
|
*render(ctx) {
|
|
3369
3743
|
ctx.bottom()[this.key] = yield this.value.value(ctx, this.liquid.options.lenientIf);
|
|
3370
3744
|
}
|
|
3745
|
+
*arguments() {
|
|
3746
|
+
yield this.value;
|
|
3747
|
+
}
|
|
3748
|
+
*localScope() {
|
|
3749
|
+
yield this.identifier;
|
|
3750
|
+
}
|
|
3371
3751
|
}
|
|
3372
3752
|
|
|
3373
3753
|
const MODIFIERS = ['offset', 'limit', 'reversed'];
|
|
@@ -3382,7 +3762,7 @@ class ForTag extends Tag {
|
|
|
3382
3762
|
}
|
|
3383
3763
|
this.variable = variable.content;
|
|
3384
3764
|
this.collection = collection;
|
|
3385
|
-
this.hash = new Hash(this.tokenizer
|
|
3765
|
+
this.hash = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
|
|
3386
3766
|
this.templates = [];
|
|
3387
3767
|
this.elseTemplates = [];
|
|
3388
3768
|
let p;
|
|
@@ -3420,16 +3800,33 @@ class ForTag extends Tag {
|
|
|
3420
3800
|
ctx.push(scope);
|
|
3421
3801
|
for (const item of collection) {
|
|
3422
3802
|
scope[this.variable] = item;
|
|
3803
|
+
ctx.continueCalled = ctx.breakCalled = false;
|
|
3423
3804
|
yield r.renderTemplates(this.templates, ctx, emitter);
|
|
3424
|
-
if (
|
|
3425
|
-
emitter['break'] = false;
|
|
3805
|
+
if (ctx.breakCalled)
|
|
3426
3806
|
break;
|
|
3427
|
-
}
|
|
3428
|
-
emitter['continue'] = false;
|
|
3429
3807
|
scope.forloop.next();
|
|
3430
3808
|
}
|
|
3809
|
+
ctx.continueCalled = ctx.breakCalled = false;
|
|
3431
3810
|
ctx.pop();
|
|
3432
3811
|
}
|
|
3812
|
+
*children() {
|
|
3813
|
+
const templates = this.templates.slice();
|
|
3814
|
+
if (this.elseTemplates) {
|
|
3815
|
+
templates.push(...this.elseTemplates);
|
|
3816
|
+
}
|
|
3817
|
+
return templates;
|
|
3818
|
+
}
|
|
3819
|
+
*arguments() {
|
|
3820
|
+
yield this.collection;
|
|
3821
|
+
for (const v of Object.values(this.hash.hash)) {
|
|
3822
|
+
if (isValueToken(v)) {
|
|
3823
|
+
yield v;
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
blockScope() {
|
|
3828
|
+
return [this.variable, 'forloop'];
|
|
3829
|
+
}
|
|
3433
3830
|
}
|
|
3434
3831
|
function reversed(arr) {
|
|
3435
3832
|
return [...arr].reverse();
|
|
@@ -3445,7 +3842,8 @@ class CaptureTag extends Tag {
|
|
|
3445
3842
|
constructor(tagToken, remainTokens, liquid, parser) {
|
|
3446
3843
|
super(tagToken, remainTokens, liquid);
|
|
3447
3844
|
this.templates = [];
|
|
3448
|
-
this.
|
|
3845
|
+
this.identifier = this.readVariable();
|
|
3846
|
+
this.variable = this.identifier.content;
|
|
3449
3847
|
while (remainTokens.length) {
|
|
3450
3848
|
const token = remainTokens.shift();
|
|
3451
3849
|
if (isTagToken(token) && token.name === 'endcapture')
|
|
@@ -3454,19 +3852,25 @@ class CaptureTag extends Tag {
|
|
|
3454
3852
|
}
|
|
3455
3853
|
throw new Error(`tag ${tagToken.getText()} not closed`);
|
|
3456
3854
|
}
|
|
3855
|
+
readVariable() {
|
|
3856
|
+
let ident = this.tokenizer.readIdentifier();
|
|
3857
|
+
if (ident.content)
|
|
3858
|
+
return ident;
|
|
3859
|
+
ident = this.tokenizer.readQuoted();
|
|
3860
|
+
if (ident)
|
|
3861
|
+
return ident;
|
|
3862
|
+
throw this.tokenizer.error('invalid capture name');
|
|
3863
|
+
}
|
|
3457
3864
|
*render(ctx) {
|
|
3458
3865
|
const r = this.liquid.renderer;
|
|
3459
3866
|
const html = yield r.renderTemplates(this.templates, ctx);
|
|
3460
3867
|
ctx.bottom()[this.variable] = html;
|
|
3461
3868
|
}
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
if (quoted)
|
|
3468
|
-
return evalQuotedToken(quoted);
|
|
3469
|
-
throw this.tokenizer.error('invalid capture name');
|
|
3869
|
+
*children() {
|
|
3870
|
+
return this.templates;
|
|
3871
|
+
}
|
|
3872
|
+
*localScope() {
|
|
3873
|
+
yield this.identifier;
|
|
3470
3874
|
}
|
|
3471
3875
|
}
|
|
3472
3876
|
|
|
@@ -3534,6 +3938,17 @@ class CaseTag extends Tag {
|
|
|
3534
3938
|
yield r.renderTemplates(this.elseTemplates, ctx, emitter);
|
|
3535
3939
|
}
|
|
3536
3940
|
}
|
|
3941
|
+
*arguments() {
|
|
3942
|
+
yield this.value;
|
|
3943
|
+
yield* this.branches.flatMap(b => b.values);
|
|
3944
|
+
}
|
|
3945
|
+
*children() {
|
|
3946
|
+
const templates = this.branches.flatMap(b => b.templates);
|
|
3947
|
+
if (this.elseTemplates) {
|
|
3948
|
+
templates.push(...this.elseTemplates);
|
|
3949
|
+
}
|
|
3950
|
+
return templates;
|
|
3951
|
+
}
|
|
3537
3952
|
}
|
|
3538
3953
|
|
|
3539
3954
|
class CommentTag extends Tag {
|
|
@@ -3587,7 +4002,7 @@ class RenderTag extends Tag {
|
|
|
3587
4002
|
tokenizer.p = begin;
|
|
3588
4003
|
break;
|
|
3589
4004
|
}
|
|
3590
|
-
this.hash = new Hash(tokenizer
|
|
4005
|
+
this.hash = new Hash(tokenizer, liquid.options.keyValueSeparator);
|
|
3591
4006
|
}
|
|
3592
4007
|
*render(ctx, emitter) {
|
|
3593
4008
|
const { liquid, hash } = this;
|
|
@@ -3616,6 +4031,55 @@ class RenderTag extends Tag {
|
|
|
3616
4031
|
yield liquid.renderer.renderTemplates(templates, childCtx, emitter);
|
|
3617
4032
|
}
|
|
3618
4033
|
}
|
|
4034
|
+
*children(partials, sync) {
|
|
4035
|
+
if (partials && isString(this['file'])) {
|
|
4036
|
+
return (yield this.liquid._parsePartialFile(this['file'], sync, this['currentFile']));
|
|
4037
|
+
}
|
|
4038
|
+
return [];
|
|
4039
|
+
}
|
|
4040
|
+
partialScope() {
|
|
4041
|
+
if (isString(this['file'])) {
|
|
4042
|
+
const names = Object.keys(this.hash.hash);
|
|
4043
|
+
if (this['with']) {
|
|
4044
|
+
const { value, alias } = this['with'];
|
|
4045
|
+
if (isString(alias)) {
|
|
4046
|
+
names.push([alias, value]);
|
|
4047
|
+
}
|
|
4048
|
+
else if (isString(this.file)) {
|
|
4049
|
+
names.push([this.file, value]);
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
if (this['for']) {
|
|
4053
|
+
const { value, alias } = this['for'];
|
|
4054
|
+
if (isString(alias)) {
|
|
4055
|
+
names.push([alias, value]);
|
|
4056
|
+
}
|
|
4057
|
+
else if (isString(this.file)) {
|
|
4058
|
+
names.push([this.file, value]);
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
return { name: this['file'], isolated: true, scope: names };
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
*arguments() {
|
|
4065
|
+
for (const v of Object.values(this.hash.hash)) {
|
|
4066
|
+
if (isValueToken(v)) {
|
|
4067
|
+
yield v;
|
|
4068
|
+
}
|
|
4069
|
+
}
|
|
4070
|
+
if (this['with']) {
|
|
4071
|
+
const { value } = this['with'];
|
|
4072
|
+
if (isValueToken(value)) {
|
|
4073
|
+
yield value;
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
if (this['for']) {
|
|
4077
|
+
const { value } = this['for'];
|
|
4078
|
+
if (isValueToken(value)) {
|
|
4079
|
+
yield value;
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
3619
4083
|
}
|
|
3620
4084
|
/**
|
|
3621
4085
|
* @return null for "none",
|
|
@@ -3672,7 +4136,7 @@ class IncludeTag extends Tag {
|
|
|
3672
4136
|
}
|
|
3673
4137
|
else
|
|
3674
4138
|
tokenizer.p = begin;
|
|
3675
|
-
this.hash = new Hash(tokenizer
|
|
4139
|
+
this.hash = new Hash(tokenizer, liquid.options.jekyllInclude || liquid.options.keyValueSeparator);
|
|
3676
4140
|
}
|
|
3677
4141
|
*render(ctx, emitter) {
|
|
3678
4142
|
const { liquid, hash, withVar } = this;
|
|
@@ -3691,12 +4155,43 @@ class IncludeTag extends Tag {
|
|
|
3691
4155
|
ctx.pop();
|
|
3692
4156
|
ctx.restoreRegister(saved);
|
|
3693
4157
|
}
|
|
4158
|
+
*children(partials, sync) {
|
|
4159
|
+
if (partials && isString(this['file'])) {
|
|
4160
|
+
return (yield this.liquid._parsePartialFile(this['file'], sync, this['currentFile']));
|
|
4161
|
+
}
|
|
4162
|
+
return [];
|
|
4163
|
+
}
|
|
4164
|
+
partialScope() {
|
|
4165
|
+
if (isString(this['file'])) {
|
|
4166
|
+
let names;
|
|
4167
|
+
if (this.liquid.options.jekyllInclude) {
|
|
4168
|
+
names = ['include'];
|
|
4169
|
+
}
|
|
4170
|
+
else {
|
|
4171
|
+
names = Object.keys(this.hash.hash);
|
|
4172
|
+
if (this.withVar) {
|
|
4173
|
+
names.push([this['file'], this.withVar]);
|
|
4174
|
+
}
|
|
4175
|
+
}
|
|
4176
|
+
return { name: this['file'], isolated: false, scope: names };
|
|
4177
|
+
}
|
|
4178
|
+
}
|
|
4179
|
+
*arguments() {
|
|
4180
|
+
yield* Object.values(this.hash.hash).filter(isValueToken);
|
|
4181
|
+
if (isValueToken(this['file'])) {
|
|
4182
|
+
yield this['file'];
|
|
4183
|
+
}
|
|
4184
|
+
if (isValueToken(this.withVar)) {
|
|
4185
|
+
yield this.withVar;
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
3694
4188
|
}
|
|
3695
4189
|
|
|
3696
4190
|
class DecrementTag extends Tag {
|
|
3697
4191
|
constructor(token, remainTokens, liquid) {
|
|
3698
4192
|
super(token, remainTokens, liquid);
|
|
3699
|
-
this.
|
|
4193
|
+
this.identifier = this.tokenizer.readIdentifier();
|
|
4194
|
+
this.variable = this.identifier.content;
|
|
3700
4195
|
}
|
|
3701
4196
|
render(context, emitter) {
|
|
3702
4197
|
const scope = context.environments;
|
|
@@ -3705,6 +4200,9 @@ class DecrementTag extends Tag {
|
|
|
3705
4200
|
}
|
|
3706
4201
|
emitter.write(stringify(--scope[this.variable]));
|
|
3707
4202
|
}
|
|
4203
|
+
*localScope() {
|
|
4204
|
+
yield this.identifier;
|
|
4205
|
+
}
|
|
3708
4206
|
}
|
|
3709
4207
|
|
|
3710
4208
|
class CycleTag extends Tag {
|
|
@@ -3742,6 +4240,12 @@ class CycleTag extends Tag {
|
|
|
3742
4240
|
groups[fingerprint] = idx;
|
|
3743
4241
|
return yield evalToken(candidate, ctx);
|
|
3744
4242
|
}
|
|
4243
|
+
*arguments() {
|
|
4244
|
+
yield* this.candidates;
|
|
4245
|
+
if (this.group) {
|
|
4246
|
+
yield this.group;
|
|
4247
|
+
}
|
|
4248
|
+
}
|
|
3745
4249
|
}
|
|
3746
4250
|
|
|
3747
4251
|
class IfTag extends Tag {
|
|
@@ -3751,13 +4255,13 @@ class IfTag extends Tag {
|
|
|
3751
4255
|
let p = [];
|
|
3752
4256
|
parser.parseStream(remainTokens)
|
|
3753
4257
|
.on('start', () => this.branches.push({
|
|
3754
|
-
value: new Value(tagToken.
|
|
4258
|
+
value: new Value(tagToken.tokenizer.readFilteredValue(), this.liquid),
|
|
3755
4259
|
templates: (p = [])
|
|
3756
4260
|
}))
|
|
3757
4261
|
.on('tag:elsif', (token) => {
|
|
3758
4262
|
assert(!this.elseTemplates, 'unexpected elsif after else');
|
|
3759
4263
|
this.branches.push({
|
|
3760
|
-
value: new Value(token.
|
|
4264
|
+
value: new Value(token.tokenizer.readFilteredValue(), this.liquid),
|
|
3761
4265
|
templates: (p = [])
|
|
3762
4266
|
});
|
|
3763
4267
|
})
|
|
@@ -3782,12 +4286,23 @@ class IfTag extends Tag {
|
|
|
3782
4286
|
}
|
|
3783
4287
|
yield r.renderTemplates(this.elseTemplates || [], ctx, emitter);
|
|
3784
4288
|
}
|
|
4289
|
+
*children() {
|
|
4290
|
+
const templates = this.branches.flatMap(b => b.templates);
|
|
4291
|
+
if (this.elseTemplates) {
|
|
4292
|
+
templates.push(...this.elseTemplates);
|
|
4293
|
+
}
|
|
4294
|
+
return templates;
|
|
4295
|
+
}
|
|
4296
|
+
arguments() {
|
|
4297
|
+
return this.branches.map(b => b.value);
|
|
4298
|
+
}
|
|
3785
4299
|
}
|
|
3786
4300
|
|
|
3787
4301
|
class IncrementTag extends Tag {
|
|
3788
4302
|
constructor(token, remainTokens, liquid) {
|
|
3789
4303
|
super(token, remainTokens, liquid);
|
|
3790
|
-
this.
|
|
4304
|
+
this.identifier = this.tokenizer.readIdentifier();
|
|
4305
|
+
this.variable = this.identifier.content;
|
|
3791
4306
|
}
|
|
3792
4307
|
render(context, emitter) {
|
|
3793
4308
|
const scope = context.environments;
|
|
@@ -3798,6 +4313,9 @@ class IncrementTag extends Tag {
|
|
|
3798
4313
|
scope[this.variable]++;
|
|
3799
4314
|
emitter.write(stringify(val));
|
|
3800
4315
|
}
|
|
4316
|
+
*localScope() {
|
|
4317
|
+
yield this.identifier;
|
|
4318
|
+
}
|
|
3801
4319
|
}
|
|
3802
4320
|
|
|
3803
4321
|
class LayoutTag extends Tag {
|
|
@@ -3805,7 +4323,7 @@ class LayoutTag extends Tag {
|
|
|
3805
4323
|
super(token, remainTokens, liquid);
|
|
3806
4324
|
this.file = parseFilePath(this.tokenizer, this.liquid, parser);
|
|
3807
4325
|
this['currentFile'] = token.file;
|
|
3808
|
-
this.args = new Hash(this.tokenizer
|
|
4326
|
+
this.args = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
|
|
3809
4327
|
this.templates = parser.parseTokens(remainTokens);
|
|
3810
4328
|
}
|
|
3811
4329
|
*render(ctx, emitter) {
|
|
@@ -3832,6 +4350,28 @@ class LayoutTag extends Tag {
|
|
|
3832
4350
|
yield renderer.renderTemplates(templates, ctx, emitter);
|
|
3833
4351
|
ctx.pop();
|
|
3834
4352
|
}
|
|
4353
|
+
*children(partials) {
|
|
4354
|
+
const templates = this.templates.slice();
|
|
4355
|
+
if (partials && isString(this.file)) {
|
|
4356
|
+
templates.push(...(yield this.liquid._parsePartialFile(this.file, true, this['currentFile'])));
|
|
4357
|
+
}
|
|
4358
|
+
return templates;
|
|
4359
|
+
}
|
|
4360
|
+
*arguments() {
|
|
4361
|
+
for (const v of Object.values(this.args.hash)) {
|
|
4362
|
+
if (isValueToken(v)) {
|
|
4363
|
+
yield v;
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4366
|
+
if (isValueToken(this.file)) {
|
|
4367
|
+
yield this.file;
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
partialScope() {
|
|
4371
|
+
if (isString(this.file)) {
|
|
4372
|
+
return { name: this.file, isolated: false, scope: Object.keys(this.args.hash) };
|
|
4373
|
+
}
|
|
4374
|
+
}
|
|
3835
4375
|
}
|
|
3836
4376
|
|
|
3837
4377
|
class BlockTag extends Tag {
|
|
@@ -3871,6 +4411,12 @@ class BlockTag extends Tag {
|
|
|
3871
4411
|
? (superBlock, emitter) => renderChild(new BlockDrop(() => renderCurrent(superBlock, emitter)), emitter)
|
|
3872
4412
|
: renderCurrent;
|
|
3873
4413
|
}
|
|
4414
|
+
*children() {
|
|
4415
|
+
return this.templates;
|
|
4416
|
+
}
|
|
4417
|
+
blockScope() {
|
|
4418
|
+
return ['block'];
|
|
4419
|
+
}
|
|
3874
4420
|
}
|
|
3875
4421
|
|
|
3876
4422
|
class RawTag extends Tag {
|
|
@@ -3925,7 +4471,7 @@ class TablerowTag extends Tag {
|
|
|
3925
4471
|
}
|
|
3926
4472
|
this.variable = variable.content;
|
|
3927
4473
|
this.collection = collectionToken;
|
|
3928
|
-
this.args = new Hash(this.tokenizer
|
|
4474
|
+
this.args = new Hash(this.tokenizer, liquid.options.keyValueSeparator);
|
|
3929
4475
|
this.templates = [];
|
|
3930
4476
|
let p;
|
|
3931
4477
|
const stream = parser.parseStream(remainTokens)
|
|
@@ -3963,6 +4509,20 @@ class TablerowTag extends Tag {
|
|
|
3963
4509
|
emitter.write('</tr>');
|
|
3964
4510
|
ctx.pop();
|
|
3965
4511
|
}
|
|
4512
|
+
*children() {
|
|
4513
|
+
return this.templates;
|
|
4514
|
+
}
|
|
4515
|
+
*arguments() {
|
|
4516
|
+
yield this.collection;
|
|
4517
|
+
for (const v of Object.values(this.args.hash)) {
|
|
4518
|
+
if (isValueToken(v)) {
|
|
4519
|
+
yield v;
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4522
|
+
}
|
|
4523
|
+
blockScope() {
|
|
4524
|
+
return [this.variable, 'tablerowloop'];
|
|
4525
|
+
}
|
|
3966
4526
|
}
|
|
3967
4527
|
|
|
3968
4528
|
class UnlessTag extends Tag {
|
|
@@ -3974,7 +4534,7 @@ class UnlessTag extends Tag {
|
|
|
3974
4534
|
let elseCount = 0;
|
|
3975
4535
|
parser.parseStream(remainTokens)
|
|
3976
4536
|
.on('start', () => this.branches.push({
|
|
3977
|
-
value: new Value(tagToken.
|
|
4537
|
+
value: new Value(tagToken.tokenizer.readFilteredValue(), this.liquid),
|
|
3978
4538
|
test: isFalsy,
|
|
3979
4539
|
templates: (p = [])
|
|
3980
4540
|
}))
|
|
@@ -3984,7 +4544,7 @@ class UnlessTag extends Tag {
|
|
|
3984
4544
|
return;
|
|
3985
4545
|
}
|
|
3986
4546
|
this.branches.push({
|
|
3987
|
-
value: new Value(token.
|
|
4547
|
+
value: new Value(token.tokenizer.readFilteredValue(), this.liquid),
|
|
3988
4548
|
test: isTruthy,
|
|
3989
4549
|
templates: (p = [])
|
|
3990
4550
|
});
|
|
@@ -4013,17 +4573,27 @@ class UnlessTag extends Tag {
|
|
|
4013
4573
|
}
|
|
4014
4574
|
yield r.renderTemplates(this.elseTemplates, ctx, emitter);
|
|
4015
4575
|
}
|
|
4576
|
+
*children() {
|
|
4577
|
+
const children = this.branches.flatMap(b => b.templates);
|
|
4578
|
+
if (this.elseTemplates) {
|
|
4579
|
+
children.push(...this.elseTemplates);
|
|
4580
|
+
}
|
|
4581
|
+
return children;
|
|
4582
|
+
}
|
|
4583
|
+
arguments() {
|
|
4584
|
+
return this.branches.map(b => b.value);
|
|
4585
|
+
}
|
|
4016
4586
|
}
|
|
4017
4587
|
|
|
4018
4588
|
class BreakTag extends Tag {
|
|
4019
|
-
render(ctx,
|
|
4020
|
-
|
|
4589
|
+
render(ctx, _emitter) {
|
|
4590
|
+
ctx.breakCalled = true;
|
|
4021
4591
|
}
|
|
4022
4592
|
}
|
|
4023
4593
|
|
|
4024
4594
|
class ContinueTag extends Tag {
|
|
4025
|
-
render(ctx,
|
|
4026
|
-
|
|
4595
|
+
render(ctx, _emitter) {
|
|
4596
|
+
ctx.continueCalled = true;
|
|
4027
4597
|
}
|
|
4028
4598
|
}
|
|
4029
4599
|
|
|
@@ -4041,6 +4611,11 @@ class EchoTag extends Tag {
|
|
|
4041
4611
|
const val = yield this.value.value(ctx, false);
|
|
4042
4612
|
emitter.write(val);
|
|
4043
4613
|
}
|
|
4614
|
+
*arguments() {
|
|
4615
|
+
if (this.value) {
|
|
4616
|
+
yield this.value;
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4044
4619
|
}
|
|
4045
4620
|
|
|
4046
4621
|
class LiquidTag extends Tag {
|
|
@@ -4052,6 +4627,9 @@ class LiquidTag extends Tag {
|
|
|
4052
4627
|
*render(ctx, emitter) {
|
|
4053
4628
|
yield this.liquid.renderer.renderTemplates(this.templates, ctx, emitter);
|
|
4054
4629
|
}
|
|
4630
|
+
*children() {
|
|
4631
|
+
return this.templates;
|
|
4632
|
+
}
|
|
4055
4633
|
}
|
|
4056
4634
|
|
|
4057
4635
|
class InlineCommentTag extends Tag {
|
|
@@ -4190,10 +4768,82 @@ class Liquid {
|
|
|
4190
4768
|
self.renderFile(filePath, ctx).then(html => callback(null, html), callback);
|
|
4191
4769
|
};
|
|
4192
4770
|
}
|
|
4771
|
+
async analyze(template, options = {}) {
|
|
4772
|
+
return analyze(template, options);
|
|
4773
|
+
}
|
|
4774
|
+
analyzeSync(template, options = {}) {
|
|
4775
|
+
return analyzeSync(template, options);
|
|
4776
|
+
}
|
|
4777
|
+
async parseAndAnalyze(html, filename, options = {}) {
|
|
4778
|
+
return analyze(this.parse(html, filename), options);
|
|
4779
|
+
}
|
|
4780
|
+
parseAndAnalyzeSync(html, filename, options = {}) {
|
|
4781
|
+
return analyzeSync(this.parse(html, filename), options);
|
|
4782
|
+
}
|
|
4783
|
+
/** Return an array of all variables without their properties. */
|
|
4784
|
+
async variables(template, options = {}) {
|
|
4785
|
+
const analysis = await analyze(isString(template) ? this.parse(template) : template, options);
|
|
4786
|
+
return Object.keys(analysis.variables);
|
|
4787
|
+
}
|
|
4788
|
+
/** Return an array of all variables without their properties. */
|
|
4789
|
+
variablesSync(template, options = {}) {
|
|
4790
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
4791
|
+
return Object.keys(analysis.variables);
|
|
4792
|
+
}
|
|
4793
|
+
/** Return an array of all variables including their properties/paths. */
|
|
4794
|
+
async fullVariables(template, options = {}) {
|
|
4795
|
+
const analysis = await analyze(isString(template) ? this.parse(template) : template, options);
|
|
4796
|
+
return Array.from(new Set(Object.values(analysis.variables).flatMap((a) => a.map((v) => String(v)))));
|
|
4797
|
+
}
|
|
4798
|
+
/** Return an array of all variables including their properties/paths. */
|
|
4799
|
+
fullVariablesSync(template, options = {}) {
|
|
4800
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
4801
|
+
return Array.from(new Set(Object.values(analysis.variables).flatMap((a) => a.map((v) => String(v)))));
|
|
4802
|
+
}
|
|
4803
|
+
/** Return an array of all variables, each as an array of properties/segments. */
|
|
4804
|
+
async variableSegments(template, options = {}) {
|
|
4805
|
+
const analysis = await analyze(isString(template) ? this.parse(template) : template, options);
|
|
4806
|
+
return Array.from(strictUniq(Object.values(analysis.variables).flatMap((a) => a.map((v) => v.toArray()))));
|
|
4807
|
+
}
|
|
4808
|
+
/** Return an array of all variables, each as an array of properties/segments. */
|
|
4809
|
+
variableSegmentsSync(template, options = {}) {
|
|
4810
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
4811
|
+
return Array.from(strictUniq(Object.values(analysis.variables).flatMap((a) => a.map((v) => v.toArray()))));
|
|
4812
|
+
}
|
|
4813
|
+
/** Return an array of all expected context variables without their properties. */
|
|
4814
|
+
async globalVariables(template, options = {}) {
|
|
4815
|
+
const analysis = await analyze(isString(template) ? this.parse(template) : template, options);
|
|
4816
|
+
return Object.keys(analysis.globals);
|
|
4817
|
+
}
|
|
4818
|
+
/** Return an array of all expected context variables without their properties. */
|
|
4819
|
+
globalVariablesSync(template, options = {}) {
|
|
4820
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
4821
|
+
return Object.keys(analysis.globals);
|
|
4822
|
+
}
|
|
4823
|
+
/** Return an array of all expected context variables including their properties/paths. */
|
|
4824
|
+
async globalFullVariables(template, options = {}) {
|
|
4825
|
+
const analysis = await analyze(isString(template) ? this.parse(template) : template, options);
|
|
4826
|
+
return Array.from(new Set(Object.values(analysis.globals).flatMap((a) => a.map((v) => String(v)))));
|
|
4827
|
+
}
|
|
4828
|
+
/** Return an array of all expected context variables including their properties/paths. */
|
|
4829
|
+
globalFullVariablesSync(template, options = {}) {
|
|
4830
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
4831
|
+
return Array.from(new Set(Object.values(analysis.globals).flatMap((a) => a.map((v) => String(v)))));
|
|
4832
|
+
}
|
|
4833
|
+
/** Return an array of all expected context variables, each as an array of properties/segments. */
|
|
4834
|
+
async globalVariableSegments(template, options = {}) {
|
|
4835
|
+
const analysis = await analyze(isString(template) ? this.parse(template) : template, options);
|
|
4836
|
+
return Array.from(strictUniq(Object.values(analysis.globals).flatMap((a) => a.map((v) => v.toArray()))));
|
|
4837
|
+
}
|
|
4838
|
+
/** Return an array of all expected context variables, each as an array of properties/segments. */
|
|
4839
|
+
globalVariableSegmentsSync(template, options = {}) {
|
|
4840
|
+
const analysis = analyzeSync(isString(template) ? this.parse(template) : template, options);
|
|
4841
|
+
return Array.from(strictUniq(Object.values(analysis.globals).flatMap((a) => a.map((v) => v.toArray()))));
|
|
4842
|
+
}
|
|
4193
4843
|
}
|
|
4194
4844
|
|
|
4195
4845
|
/* istanbul ignore file */
|
|
4196
|
-
const version = '10.
|
|
4846
|
+
const version = '10.20.1';
|
|
4197
4847
|
|
|
4198
4848
|
exports.AssertionError = AssertionError;
|
|
4199
4849
|
exports.AssignTag = AssignTag;
|
|
@@ -4223,6 +4873,7 @@ exports.LiquidTag = LiquidTag;
|
|
|
4223
4873
|
exports.Output = Output;
|
|
4224
4874
|
exports.ParseError = ParseError;
|
|
4225
4875
|
exports.ParseStream = ParseStream;
|
|
4876
|
+
exports.Parser = Parser;
|
|
4226
4877
|
exports.RawTag = RawTag;
|
|
4227
4878
|
exports.RenderError = RenderError;
|
|
4228
4879
|
exports.RenderTag = RenderTag;
|
|
@@ -4236,6 +4887,9 @@ exports.TypeGuards = typeGuards;
|
|
|
4236
4887
|
exports.UndefinedVariableError = UndefinedVariableError;
|
|
4237
4888
|
exports.UnlessTag = UnlessTag;
|
|
4238
4889
|
exports.Value = Value;
|
|
4890
|
+
exports.Variable = Variable;
|
|
4891
|
+
exports.analyze = analyze;
|
|
4892
|
+
exports.analyzeSync = analyzeSync;
|
|
4239
4893
|
exports.assert = assert;
|
|
4240
4894
|
exports.createTrie = createTrie;
|
|
4241
4895
|
exports.defaultOperators = defaultOperators;
|