@platformos/liquid-html-parser 0.0.15 → 0.0.17
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/stage-1-cst.d.ts +1 -6
- package/dist/stage-1-cst.js +12 -22
- package/dist/stage-2-ast.d.ts +3 -10
- package/dist/stage-2-ast.js +1 -13
- package/dist/types.d.ts +0 -1
- package/dist/types.js +0 -1
- package/grammar/liquid-html.ohm +55 -17
- package/grammar/liquid-html.ohm.js +55 -17
- package/package.json +1 -1
package/dist/stage-1-cst.d.ts
CHANGED
|
@@ -63,7 +63,6 @@ export declare enum ConcreteNodeTypes {
|
|
|
63
63
|
Comparison = "Comparison",
|
|
64
64
|
Condition = "Condition",
|
|
65
65
|
AssignMarkup = "AssignMarkup",
|
|
66
|
-
AssignPushRhs = "AssignPushRhs",
|
|
67
66
|
HashAssignMarkup = "HashAssignMarkup",
|
|
68
67
|
ContentForMarkup = "ContentForMarkup",
|
|
69
68
|
CycleMarkup = "CycleMarkup",
|
|
@@ -267,15 +266,11 @@ export interface ConcreteLiquidTagLiquid extends ConcreteLiquidTagNode<NamedTags
|
|
|
267
266
|
export type ConcreteLiquidLiquidTagNode = ConcreteLiquidTagOpen | ConcreteLiquidTagClose | ConcreteLiquidTag | ConcreteLiquidRawTag;
|
|
268
267
|
export interface ConcreteLiquidTagAssign extends ConcreteLiquidTagNode<NamedTags.assign, ConcreteLiquidTagAssignMarkup> {
|
|
269
268
|
}
|
|
270
|
-
export interface ConcreteLiquidTagAssignPushRhs extends ConcreteBasicNode<ConcreteNodeTypes.AssignPushRhs> {
|
|
271
|
-
pushSource: ConcreteLiquidVariable;
|
|
272
|
-
pushValue: ConcreteLiquidVariable;
|
|
273
|
-
}
|
|
274
269
|
export interface ConcreteLiquidTagAssignMarkup extends ConcreteBasicNode<ConcreteNodeTypes.AssignMarkup> {
|
|
275
270
|
name: string;
|
|
276
271
|
target: ConcreteLiquidVariableLookup;
|
|
277
272
|
operator: string;
|
|
278
|
-
value: ConcreteLiquidVariable
|
|
273
|
+
value: ConcreteLiquidVariable;
|
|
279
274
|
}
|
|
280
275
|
export interface ConcreteLiquidTagHashAssign extends ConcreteLiquidTagNode<NamedTags.hash_assign, ConcreteLiquidTagHashAssignMarkup> {
|
|
281
276
|
}
|
package/dist/stage-1-cst.js
CHANGED
|
@@ -71,7 +71,6 @@ var ConcreteNodeTypes;
|
|
|
71
71
|
ConcreteNodeTypes["Comparison"] = "Comparison";
|
|
72
72
|
ConcreteNodeTypes["Condition"] = "Condition";
|
|
73
73
|
ConcreteNodeTypes["AssignMarkup"] = "AssignMarkup";
|
|
74
|
-
ConcreteNodeTypes["AssignPushRhs"] = "AssignPushRhs";
|
|
75
74
|
ConcreteNodeTypes["HashAssignMarkup"] = "HashAssignMarkup";
|
|
76
75
|
ConcreteNodeTypes["ContentForMarkup"] = "ContentForMarkup";
|
|
77
76
|
ConcreteNodeTypes["CycleMarkup"] = "CycleMarkup";
|
|
@@ -368,25 +367,6 @@ function toCST(source /* the original file */, grammars, grammar, cstMappings, m
|
|
|
368
367
|
},
|
|
369
368
|
assignOperator: (node) => node.sourceString,
|
|
370
369
|
liquidAssignValue: 0,
|
|
371
|
-
liquidAssignPushExpr: {
|
|
372
|
-
type: ConcreteNodeTypes.AssignPushRhs,
|
|
373
|
-
// tokens: [pushSource, space*, "<<", space*, pushValue]
|
|
374
|
-
pushSource: 0,
|
|
375
|
-
pushValue: 4,
|
|
376
|
-
locStart,
|
|
377
|
-
locEnd,
|
|
378
|
-
source,
|
|
379
|
-
},
|
|
380
|
-
liquidAssignPushSource: {
|
|
381
|
-
type: ConcreteNodeTypes.LiquidVariable,
|
|
382
|
-
expression: 0,
|
|
383
|
-
filters: 1,
|
|
384
|
-
// No &delim lookahead at end (unlike liquidAssignVariable), so last token is space*
|
|
385
|
-
rawSource: (tokens) => source.slice(locStart(tokens), tokens[tokens.length - 1].source.endIdx).trimEnd(),
|
|
386
|
-
locStart,
|
|
387
|
-
locEnd,
|
|
388
|
-
source,
|
|
389
|
-
},
|
|
390
370
|
liquidAssignVariable: {
|
|
391
371
|
type: ConcreteNodeTypes.LiquidVariable,
|
|
392
372
|
expression: 0,
|
|
@@ -633,6 +613,8 @@ function toCST(source /* the original file */, grammars, grammar, cstMappings, m
|
|
|
633
613
|
liquidTagResponseHeadersMarkup: 0,
|
|
634
614
|
liquidTagRollback: 0,
|
|
635
615
|
renderArguments: 1,
|
|
616
|
+
functionRenderArguments: 1,
|
|
617
|
+
functionTagArguments: 0,
|
|
636
618
|
completionModeRenderArguments: function (_0, namedArguments, _2, _3, _4, _5, variableLookup, _7) {
|
|
637
619
|
const self = this;
|
|
638
620
|
// variableLookup.sourceString can be '' when there are no incomplete params
|
|
@@ -726,6 +708,9 @@ function toCST(source /* the original file */, grammars, grammar, cstMappings, m
|
|
|
726
708
|
tagArguments: 0,
|
|
727
709
|
graphqlArguments: 0,
|
|
728
710
|
graphqlRenderArguments: 1,
|
|
711
|
+
// Pass-through: delegates to whichever alternative matched (liquidJsonHashLiteral,
|
|
712
|
+
// liquidJsonArrayLiteral, or liquidExpression). Index 0 = first (and only) child.
|
|
713
|
+
liquidExpressionOrJsonLiteral: 0,
|
|
729
714
|
positionalArgument: 0,
|
|
730
715
|
namedArgument: {
|
|
731
716
|
type: ConcreteNodeTypes.NamedArgument,
|
|
@@ -736,6 +721,9 @@ function toCST(source /* the original file */, grammars, grammar, cstMappings, m
|
|
|
736
721
|
source,
|
|
737
722
|
},
|
|
738
723
|
namedArgumentValue: 0,
|
|
724
|
+
// Handles nested key:value pairs within a named argument value, e.g. `filter: type: "string"`.
|
|
725
|
+
// Only fires when the namedArgumentValue starts with `identifier:`.
|
|
726
|
+
// Produces a NamedArgument so linters can inspect the nested pair.
|
|
739
727
|
hashPairValue: {
|
|
740
728
|
type: ConcreteNodeTypes.NamedArgument,
|
|
741
729
|
name: 0,
|
|
@@ -799,7 +787,9 @@ function toCST(source /* the original file */, grammars, grammar, cstMappings, m
|
|
|
799
787
|
liquidDoubleQuotedString: {
|
|
800
788
|
type: ConcreteNodeTypes.String,
|
|
801
789
|
single: () => false,
|
|
802
|
-
|
|
790
|
+
// body is an iteration node (strings now support `\X` escape pairs); use
|
|
791
|
+
// `.sourceString` to get the raw text between quotes.
|
|
792
|
+
value: (tokens) => tokens[1].sourceString,
|
|
803
793
|
locStart,
|
|
804
794
|
locEnd,
|
|
805
795
|
source,
|
|
@@ -807,7 +797,7 @@ function toCST(source /* the original file */, grammars, grammar, cstMappings, m
|
|
|
807
797
|
liquidSingleQuotedString: {
|
|
808
798
|
type: ConcreteNodeTypes.String,
|
|
809
799
|
single: () => true,
|
|
810
|
-
value: 1,
|
|
800
|
+
value: (tokens) => tokens[1].sourceString,
|
|
811
801
|
locStart,
|
|
812
802
|
locEnd,
|
|
813
803
|
source,
|
package/dist/stage-2-ast.d.ts
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
import { ConcreteAttributeNode, ConcreteHtmlTagClose, ConcreteLiquidTagClose, LiquidCST, LiquidHtmlCST, ConcreteLiquidLiteral } from './stage-1-cst';
|
|
36
36
|
import { Comparators, NamedTags, NodeTypes, Position } from './types';
|
|
37
37
|
/** The union type of all possible node types inside a LiquidHTML AST. */
|
|
38
|
-
export type LiquidHtmlNode = DocumentNode | YAMLFrontmatter | LiquidNode | HtmlDoctype | HtmlNode | AttributeNode | LiquidVariable | ComplexLiquidExpression | LiquidFilter | LiquidNamedArgument | AssignMarkup |
|
|
38
|
+
export type LiquidHtmlNode = DocumentNode | YAMLFrontmatter | LiquidNode | HtmlDoctype | HtmlNode | AttributeNode | LiquidVariable | ComplexLiquidExpression | LiquidFilter | LiquidNamedArgument | AssignMarkup | HashAssignMarkup | ContentForMarkup | CycleMarkup | ForMarkup | RenderMarkup | FunctionMarkup | GraphQLMarkup | GraphQLInlineMarkup | RawMarkup | RenderVariableExpression | RenderAliasExpression | LiquidLogicalExpression | LiquidComparison | TextNode | LiquidDocParamNode | LiquidDocExampleNode | LiquidDocPromptNode | LiquidDocDescriptionNode | JsonHashLiteral | JsonArrayLiteral | JsonKeyValuePair | BackgroundMarkup | BackgroundInlineMarkup | CacheMarkup | LogMarkup | SessionMarkup | ExportMarkup | RedirectToMarkup | IncludeFormMarkup | SpamProtectionMarkup;
|
|
39
39
|
/** The root node of all LiquidHTML ASTs. */
|
|
40
40
|
export interface DocumentNode extends ASTNode<NodeTypes.Document> {
|
|
41
41
|
children: LiquidHtmlNode[];
|
|
@@ -143,15 +143,8 @@ export interface AssignMarkup extends ASTNode<NodeTypes.AssignMarkup> {
|
|
|
143
143
|
lookups: LiquidExpression[];
|
|
144
144
|
/** '=' for assignment, '<<' for array append */
|
|
145
145
|
operator: '=' | '<<';
|
|
146
|
-
/** the value of the variable that is being assigned
|
|
147
|
-
value: LiquidVariable
|
|
148
|
-
}
|
|
149
|
-
/** The RHS of an explicit push assign: `assign a = source << value` */
|
|
150
|
-
export interface AssignPushRhs extends ASTNode<NodeTypes.AssignPushRhs> {
|
|
151
|
-
/** the source array to push into */
|
|
152
|
-
pushSource: LiquidVariable;
|
|
153
|
-
/** the value being pushed */
|
|
154
|
-
pushValue: LiquidVariable;
|
|
146
|
+
/** the value of the variable that is being assigned */
|
|
147
|
+
value: LiquidVariable;
|
|
155
148
|
}
|
|
156
149
|
export interface LiquidTagHashAssign extends LiquidTagNode<NamedTags.hash_assign, HashAssignMarkup> {
|
|
157
150
|
}
|
package/dist/stage-2-ast.js
CHANGED
|
@@ -913,24 +913,12 @@ function toUnnamedLiquidBranch(parentNode) {
|
|
|
913
913
|
};
|
|
914
914
|
}
|
|
915
915
|
function toAssignMarkup(node) {
|
|
916
|
-
const value = node.value.type === stage_1_cst_1.ConcreteNodeTypes.AssignPushRhs
|
|
917
|
-
? toAssignPushRhs(node.value)
|
|
918
|
-
: toLiquidVariable(node.value);
|
|
919
916
|
return {
|
|
920
917
|
type: types_1.NodeTypes.AssignMarkup,
|
|
921
918
|
name: node.name,
|
|
922
919
|
lookups: node.target.lookups.map(toExpression),
|
|
923
920
|
operator: node.operator,
|
|
924
|
-
value,
|
|
925
|
-
position: position(node),
|
|
926
|
-
source: node.source,
|
|
927
|
-
};
|
|
928
|
-
}
|
|
929
|
-
function toAssignPushRhs(node) {
|
|
930
|
-
return {
|
|
931
|
-
type: types_1.NodeTypes.AssignPushRhs,
|
|
932
|
-
pushSource: toLiquidVariable(node.pushSource),
|
|
933
|
-
pushValue: toLiquidVariable(node.pushValue),
|
|
921
|
+
value: toLiquidVariable(node.value),
|
|
934
922
|
position: position(node),
|
|
935
923
|
source: node.source,
|
|
936
924
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -36,7 +36,6 @@ export declare enum NodeTypes {
|
|
|
36
36
|
Comparison = "Comparison",
|
|
37
37
|
LogicalExpression = "LogicalExpression",
|
|
38
38
|
AssignMarkup = "AssignMarkup",
|
|
39
|
-
AssignPushRhs = "AssignPushRhs",
|
|
40
39
|
HashAssignMarkup = "HashAssignMarkup",
|
|
41
40
|
ContentForMarkup = "ContentForMarkup",
|
|
42
41
|
CycleMarkup = "CycleMarkup",
|
package/dist/types.js
CHANGED
|
@@ -34,7 +34,6 @@ var NodeTypes;
|
|
|
34
34
|
NodeTypes["Comparison"] = "Comparison";
|
|
35
35
|
NodeTypes["LogicalExpression"] = "LogicalExpression";
|
|
36
36
|
NodeTypes["AssignMarkup"] = "AssignMarkup";
|
|
37
|
-
NodeTypes["AssignPushRhs"] = "AssignPushRhs";
|
|
38
37
|
NodeTypes["HashAssignMarkup"] = "HashAssignMarkup";
|
|
39
38
|
NodeTypes["ContentForMarkup"] = "ContentForMarkup";
|
|
40
39
|
NodeTypes["CycleMarkup"] = "CycleMarkup";
|
package/grammar/liquid-html.ohm
CHANGED
|
@@ -130,16 +130,14 @@ Liquid <: Helpers {
|
|
|
130
130
|
|
|
131
131
|
// Assign-specific sub-rules
|
|
132
132
|
assignTarget<delim> = variableSegment lookup<delim>*
|
|
133
|
+
// Only one operator per assign: either `=` (regular assignment) or `<<` (push).
|
|
134
|
+
// The two forms are mutually exclusive — `{% assign a << "item" %}` pushes onto `a`,
|
|
135
|
+
// and `{% assign a = value %}` assigns to `a`. A compound shape like
|
|
136
|
+
// `{% assign a = b << c %}` is INVALID per the platformOS runtime.
|
|
133
137
|
assignOperator = "<<" | "="
|
|
134
138
|
|
|
135
|
-
// The RHS of an assign:
|
|
136
|
-
liquidAssignValue<delim> =
|
|
137
|
-
|
|
138
|
-
// Explicit push: assign a = source << value (equivalent to assign a << value when source is a)
|
|
139
|
-
liquidAssignPushExpr<delim> = liquidAssignPushSource<delim> space* "<<" space* liquidAssignVariable<delim>
|
|
140
|
-
|
|
141
|
-
// The source expression for a push (no &delim lookahead since "<<" follows)
|
|
142
|
-
liquidAssignPushSource<delim> = liquidAssignExpression<delim> liquidFilter<delim>* space*
|
|
139
|
+
// The RHS of an assign: a regular value (expression + optional filters).
|
|
140
|
+
liquidAssignValue<delim> = liquidAssignVariable<delim>
|
|
143
141
|
|
|
144
142
|
// Assign variable: like liquidVariable but expression allows JSON literals
|
|
145
143
|
liquidAssignVariable<delim> = liquidAssignExpression<delim> liquidFilter<delim>* space* &delim
|
|
@@ -148,7 +146,7 @@ Liquid <: Helpers {
|
|
|
148
146
|
| liquidJsonArrayLiteral<delim>
|
|
149
147
|
| liquidComplexExpression<delim>
|
|
150
148
|
|
|
151
|
-
// JSON literal rules (assign
|
|
149
|
+
// JSON literal rules (assign, return, and named argument values; recursive)
|
|
152
150
|
liquidJsonHashLiteral<delim> =
|
|
153
151
|
"{" space* listOf<liquidJsonKeyValue<delim>, liquidJsonSep> space* "}"
|
|
154
152
|
liquidJsonKeyValue<delim> =
|
|
@@ -415,8 +413,17 @@ Liquid <: Helpers {
|
|
|
415
413
|
booleanExpressionCondition<delim> = comparison<delim> | liquidExpression<delim>
|
|
416
414
|
|
|
417
415
|
liquidString<delim> = liquidSingleQuotedString<delim> | liquidDoubleQuotedString<delim>
|
|
418
|
-
|
|
419
|
-
|
|
416
|
+
// Strings support backslash-X escape pairs (any character after a backslash is
|
|
417
|
+
// consumed as part of the string). This matches the platformOS runtime, which parses
|
|
418
|
+
// hash/array literal string values with Ruby's JSON library — so an escaped quote or
|
|
419
|
+
// an escaped backslash is valid inside a double-quoted string.
|
|
420
|
+
liquidSingleQuotedString<delim> = "'" liquidSingleQuotedStringBody<delim> "'"
|
|
421
|
+
liquidDoubleQuotedString<delim> = "\"" liquidDoubleQuotedStringBody<delim> "\""
|
|
422
|
+
liquidSingleQuotedStringBody<delim> = (liquidStringEscape | liquidSingleQuotedStringChar<delim>)*
|
|
423
|
+
liquidDoubleQuotedStringBody<delim> = (liquidStringEscape | liquidDoubleQuotedStringChar<delim>)*
|
|
424
|
+
liquidSingleQuotedStringChar<delim> = ~("'" | delim) any
|
|
425
|
+
liquidDoubleQuotedStringChar<delim> = ~("\"" | delim) any
|
|
426
|
+
liquidStringEscape = "\\" any
|
|
420
427
|
|
|
421
428
|
liquidNumber = liquidFloat | liquidInteger
|
|
422
429
|
liquidInteger = "-"? digit+
|
|
@@ -449,9 +456,18 @@ Liquid <: Helpers {
|
|
|
449
456
|
arguments<delim> = nonemptyOrderedListOf<positionalArgument<delim>, namedArgument<delim>, argumentSeparator>
|
|
450
457
|
argumentSeparator = space* "," space*
|
|
451
458
|
argumentSeparatorOptionalComma = space* ","? space*
|
|
452
|
-
|
|
459
|
+
// liquidExpressionOrJsonLiteral: used in argument value positions where JSON hash/array
|
|
460
|
+
// literals are accepted (named args, filter positional args). Does NOT extend liquidExpression
|
|
461
|
+
// itself so that {{ ["x"] }} drop expressions are still parsed as VariableLookup (empty lookup).
|
|
462
|
+
liquidExpressionOrJsonLiteral<delim> = liquidJsonHashLiteral<delim> | liquidJsonArrayLiteral<delim> | liquidExpression<delim>
|
|
463
|
+
positionalArgument<delim> = liquidExpressionOrJsonLiteral<delim> ~(space* ":")
|
|
453
464
|
namedArgument<delim> = variableSegment space* ":" space* namedArgumentValue<delim>
|
|
454
|
-
namedArgumentValue<delim> = hashPairValue<delim> |
|
|
465
|
+
namedArgumentValue<delim> = hashPairValue<delim> | liquidExpressionOrJsonLiteral<delim>
|
|
466
|
+
// hashPairValue handles nested key:value pairs within a named argument value, e.g.
|
|
467
|
+
// {% function res = 'path', filter: type: "string" %}
|
|
468
|
+
// where `type: "string"` is the hashPairValue. Only fires when the value starts with
|
|
469
|
+
// `identifier:` — otherwise namedArgumentValue falls through to liquidExpressionOrJsonLiteral.
|
|
470
|
+
// Produces a NamedArgument node so linters can inspect nested argument pairs.
|
|
455
471
|
hashPairValue<delim> = variableSegment space* ":" space* liquidExpression<delim>
|
|
456
472
|
tagArguments = listOf<namedArgument<delimTag>, argumentSeparatorOptionalComma>
|
|
457
473
|
graphqlArguments = listOf<graphqlNamedArgument, argumentSeparatorOptionalComma>
|
|
@@ -574,10 +590,11 @@ LiquidStatement <: Liquid {
|
|
|
574
590
|
|
|
575
591
|
// Override string rules so that '#' inside string content is never mistaken for a
|
|
576
592
|
// delimTag inline-comment marker. In LiquidStatement, delimTag includes `# ...` which
|
|
577
|
-
// would otherwise cause
|
|
578
|
-
// Strings in liquid blocks end at the matching quote or at a newline (no multi-line
|
|
579
|
-
|
|
580
|
-
|
|
593
|
+
// would otherwise cause the body rule to stop inside strings like '##label##'.
|
|
594
|
+
// Strings in liquid blocks end at the matching quote or at a newline (no multi-line
|
|
595
|
+
// strings), but still support `\X` escape pairs.
|
|
596
|
+
liquidSingleQuotedStringChar<delim> := ~("'" | newline | end) any
|
|
597
|
+
liquidDoubleQuotedStringChar<delim> := ~("\"" | newline | end) any
|
|
581
598
|
|
|
582
599
|
// trailing whitespace, newline, + optional leading `;` and `# comment` before the next tag
|
|
583
600
|
statementSep = space* ";"? space* ("#" (~newline any)*)? newline (space | newline)*
|
|
@@ -585,6 +602,27 @@ LiquidStatement <: Liquid {
|
|
|
585
602
|
// delimTag is used as &delim lookahead in expression rules; it must succeed before `;` and `#`
|
|
586
603
|
liquidStatementEnd = ";"? space* ("#" (~newline any)*)? (newline | end)
|
|
587
604
|
delimTag := liquidStatementEnd
|
|
605
|
+
|
|
606
|
+
// Allow newlines inside hash/array literals within {% liquid %} blocks.
|
|
607
|
+
// The base Liquid grammar restricts `space` to horizontal whitespace only, but hash/array
|
|
608
|
+
// literals written across multiple lines need to match newlines between `{`/`[` and entries,
|
|
609
|
+
// between entries (around commas), and between the last entry and the closing `}`/`]`.
|
|
610
|
+
liquidJsonSep := (space | newline)* "," (space | newline)*
|
|
611
|
+
liquidJsonHashLiteral<delim> := "{" (space | newline)* listOf<liquidJsonKeyValue<delim>, liquidJsonSep> (space | newline)* "}"
|
|
612
|
+
liquidJsonArrayLiteral<delim> := "[" (space | newline)* listOf<liquidJsonValue<delim>, liquidJsonSep> (space | newline)* "]"
|
|
613
|
+
|
|
614
|
+
// Only the function tag supports multi-line named arguments in {% liquid %} blocks.
|
|
615
|
+
// render, include, and other tags use the base argumentSeparatorOptionalComma (horizontal-
|
|
616
|
+
// only), which prevents their argument lists from spanning lines. Function uses a dedicated
|
|
617
|
+
// separator that allows newlines ONLY after a comma, preventing the next statement from
|
|
618
|
+
// being swallowed as an argument when no comma is present.
|
|
619
|
+
//
|
|
620
|
+
// Both alternatives have 3 components (space, comma, space) to match each other's arity,
|
|
621
|
+
// ensuring consistent visitor child indexing.
|
|
622
|
+
functionArgumentSeparatorOptionalComma = space* "," (space | newline)* | space* ","? space*
|
|
623
|
+
functionTagArguments = listOf<namedArgument<delimTag>, functionArgumentSeparatorOptionalComma>
|
|
624
|
+
functionRenderArguments = (functionArgumentSeparatorOptionalComma functionTagArguments) (space* ",")? space*
|
|
625
|
+
liquidTagFunctionMarkup := liquidVariableLookup<delimTag> space* "=" space* partialExpression functionRenderArguments liquidFilter<delimTag>* space*
|
|
588
626
|
}
|
|
589
627
|
|
|
590
628
|
LiquidDoc <: Helpers {
|
|
@@ -130,16 +130,14 @@ Liquid <: Helpers {
|
|
|
130
130
|
|
|
131
131
|
// Assign-specific sub-rules
|
|
132
132
|
assignTarget<delim> = variableSegment lookup<delim>*
|
|
133
|
+
// Only one operator per assign: either ${"`"}=${"`"} (regular assignment) or ${"`"}<<${"`"} (push).
|
|
134
|
+
// The two forms are mutually exclusive — ${"`"}{% assign a << "item" %}${"`"} pushes onto ${"`"}a${"`"},
|
|
135
|
+
// and ${"`"}{% assign a = value %}${"`"} assigns to ${"`"}a${"`"}. A compound shape like
|
|
136
|
+
// ${"`"}{% assign a = b << c %}${"`"} is INVALID per the platformOS runtime.
|
|
133
137
|
assignOperator = "<<" | "="
|
|
134
138
|
|
|
135
|
-
// The RHS of an assign:
|
|
136
|
-
liquidAssignValue<delim> =
|
|
137
|
-
|
|
138
|
-
// Explicit push: assign a = source << value (equivalent to assign a << value when source is a)
|
|
139
|
-
liquidAssignPushExpr<delim> = liquidAssignPushSource<delim> space* "<<" space* liquidAssignVariable<delim>
|
|
140
|
-
|
|
141
|
-
// The source expression for a push (no &delim lookahead since "<<" follows)
|
|
142
|
-
liquidAssignPushSource<delim> = liquidAssignExpression<delim> liquidFilter<delim>* space*
|
|
139
|
+
// The RHS of an assign: a regular value (expression + optional filters).
|
|
140
|
+
liquidAssignValue<delim> = liquidAssignVariable<delim>
|
|
143
141
|
|
|
144
142
|
// Assign variable: like liquidVariable but expression allows JSON literals
|
|
145
143
|
liquidAssignVariable<delim> = liquidAssignExpression<delim> liquidFilter<delim>* space* &delim
|
|
@@ -148,7 +146,7 @@ Liquid <: Helpers {
|
|
|
148
146
|
| liquidJsonArrayLiteral<delim>
|
|
149
147
|
| liquidComplexExpression<delim>
|
|
150
148
|
|
|
151
|
-
// JSON literal rules (assign
|
|
149
|
+
// JSON literal rules (assign, return, and named argument values; recursive)
|
|
152
150
|
liquidJsonHashLiteral<delim> =
|
|
153
151
|
"{" space* listOf<liquidJsonKeyValue<delim>, liquidJsonSep> space* "}"
|
|
154
152
|
liquidJsonKeyValue<delim> =
|
|
@@ -415,8 +413,17 @@ Liquid <: Helpers {
|
|
|
415
413
|
booleanExpressionCondition<delim> = comparison<delim> | liquidExpression<delim>
|
|
416
414
|
|
|
417
415
|
liquidString<delim> = liquidSingleQuotedString<delim> | liquidDoubleQuotedString<delim>
|
|
418
|
-
|
|
419
|
-
|
|
416
|
+
// Strings support backslash-X escape pairs (any character after a backslash is
|
|
417
|
+
// consumed as part of the string). This matches the platformOS runtime, which parses
|
|
418
|
+
// hash/array literal string values with Ruby's JSON library — so an escaped quote or
|
|
419
|
+
// an escaped backslash is valid inside a double-quoted string.
|
|
420
|
+
liquidSingleQuotedString<delim> = "'" liquidSingleQuotedStringBody<delim> "'"
|
|
421
|
+
liquidDoubleQuotedString<delim> = "\"" liquidDoubleQuotedStringBody<delim> "\""
|
|
422
|
+
liquidSingleQuotedStringBody<delim> = (liquidStringEscape | liquidSingleQuotedStringChar<delim>)*
|
|
423
|
+
liquidDoubleQuotedStringBody<delim> = (liquidStringEscape | liquidDoubleQuotedStringChar<delim>)*
|
|
424
|
+
liquidSingleQuotedStringChar<delim> = ~("'" | delim) any
|
|
425
|
+
liquidDoubleQuotedStringChar<delim> = ~("\"" | delim) any
|
|
426
|
+
liquidStringEscape = "\\" any
|
|
420
427
|
|
|
421
428
|
liquidNumber = liquidFloat | liquidInteger
|
|
422
429
|
liquidInteger = "-"? digit+
|
|
@@ -449,9 +456,18 @@ Liquid <: Helpers {
|
|
|
449
456
|
arguments<delim> = nonemptyOrderedListOf<positionalArgument<delim>, namedArgument<delim>, argumentSeparator>
|
|
450
457
|
argumentSeparator = space* "," space*
|
|
451
458
|
argumentSeparatorOptionalComma = space* ","? space*
|
|
452
|
-
|
|
459
|
+
// liquidExpressionOrJsonLiteral: used in argument value positions where JSON hash/array
|
|
460
|
+
// literals are accepted (named args, filter positional args). Does NOT extend liquidExpression
|
|
461
|
+
// itself so that {{ ["x"] }} drop expressions are still parsed as VariableLookup (empty lookup).
|
|
462
|
+
liquidExpressionOrJsonLiteral<delim> = liquidJsonHashLiteral<delim> | liquidJsonArrayLiteral<delim> | liquidExpression<delim>
|
|
463
|
+
positionalArgument<delim> = liquidExpressionOrJsonLiteral<delim> ~(space* ":")
|
|
453
464
|
namedArgument<delim> = variableSegment space* ":" space* namedArgumentValue<delim>
|
|
454
|
-
namedArgumentValue<delim> = hashPairValue<delim> |
|
|
465
|
+
namedArgumentValue<delim> = hashPairValue<delim> | liquidExpressionOrJsonLiteral<delim>
|
|
466
|
+
// hashPairValue handles nested key:value pairs within a named argument value, e.g.
|
|
467
|
+
// {% function res = 'path', filter: type: "string" %}
|
|
468
|
+
// where ${"`"}type: "string"${"`"} is the hashPairValue. Only fires when the value starts with
|
|
469
|
+
// ${"`"}identifier:${"`"} — otherwise namedArgumentValue falls through to liquidExpressionOrJsonLiteral.
|
|
470
|
+
// Produces a NamedArgument node so linters can inspect nested argument pairs.
|
|
455
471
|
hashPairValue<delim> = variableSegment space* ":" space* liquidExpression<delim>
|
|
456
472
|
tagArguments = listOf<namedArgument<delimTag>, argumentSeparatorOptionalComma>
|
|
457
473
|
graphqlArguments = listOf<graphqlNamedArgument, argumentSeparatorOptionalComma>
|
|
@@ -574,10 +590,11 @@ LiquidStatement <: Liquid {
|
|
|
574
590
|
|
|
575
591
|
// Override string rules so that '#' inside string content is never mistaken for a
|
|
576
592
|
// delimTag inline-comment marker. In LiquidStatement, delimTag includes ${"`"}# ...${"`"} which
|
|
577
|
-
// would otherwise cause
|
|
578
|
-
// Strings in liquid blocks end at the matching quote or at a newline (no multi-line
|
|
579
|
-
|
|
580
|
-
|
|
593
|
+
// would otherwise cause the body rule to stop inside strings like '##label##'.
|
|
594
|
+
// Strings in liquid blocks end at the matching quote or at a newline (no multi-line
|
|
595
|
+
// strings), but still support ${"`"}\X${"`"} escape pairs.
|
|
596
|
+
liquidSingleQuotedStringChar<delim> := ~("'" | newline | end) any
|
|
597
|
+
liquidDoubleQuotedStringChar<delim> := ~("\"" | newline | end) any
|
|
581
598
|
|
|
582
599
|
// trailing whitespace, newline, + optional leading ${"`"};${"`"} and ${"`"}# comment${"`"} before the next tag
|
|
583
600
|
statementSep = space* ";"? space* ("#" (~newline any)*)? newline (space | newline)*
|
|
@@ -585,6 +602,27 @@ LiquidStatement <: Liquid {
|
|
|
585
602
|
// delimTag is used as &delim lookahead in expression rules; it must succeed before ${"`"};${"`"} and ${"`"}#${"`"}
|
|
586
603
|
liquidStatementEnd = ";"? space* ("#" (~newline any)*)? (newline | end)
|
|
587
604
|
delimTag := liquidStatementEnd
|
|
605
|
+
|
|
606
|
+
// Allow newlines inside hash/array literals within {% liquid %} blocks.
|
|
607
|
+
// The base Liquid grammar restricts ${"`"}space${"`"} to horizontal whitespace only, but hash/array
|
|
608
|
+
// literals written across multiple lines need to match newlines between ${"`"}{${"`"}/${"`"}[${"`"} and entries,
|
|
609
|
+
// between entries (around commas), and between the last entry and the closing ${"`"}}${"`"}/${"`"}]${"`"}.
|
|
610
|
+
liquidJsonSep := (space | newline)* "," (space | newline)*
|
|
611
|
+
liquidJsonHashLiteral<delim> := "{" (space | newline)* listOf<liquidJsonKeyValue<delim>, liquidJsonSep> (space | newline)* "}"
|
|
612
|
+
liquidJsonArrayLiteral<delim> := "[" (space | newline)* listOf<liquidJsonValue<delim>, liquidJsonSep> (space | newline)* "]"
|
|
613
|
+
|
|
614
|
+
// Only the function tag supports multi-line named arguments in {% liquid %} blocks.
|
|
615
|
+
// render, include, and other tags use the base argumentSeparatorOptionalComma (horizontal-
|
|
616
|
+
// only), which prevents their argument lists from spanning lines. Function uses a dedicated
|
|
617
|
+
// separator that allows newlines ONLY after a comma, preventing the next statement from
|
|
618
|
+
// being swallowed as an argument when no comma is present.
|
|
619
|
+
//
|
|
620
|
+
// Both alternatives have 3 components (space, comma, space) to match each other's arity,
|
|
621
|
+
// ensuring consistent visitor child indexing.
|
|
622
|
+
functionArgumentSeparatorOptionalComma = space* "," (space | newline)* | space* ","? space*
|
|
623
|
+
functionTagArguments = listOf<namedArgument<delimTag>, functionArgumentSeparatorOptionalComma>
|
|
624
|
+
functionRenderArguments = (functionArgumentSeparatorOptionalComma functionTagArguments) (space* ",")? space*
|
|
625
|
+
liquidTagFunctionMarkup := liquidVariableLookup<delimTag> space* "=" space* partialExpression functionRenderArguments liquidFilter<delimTag>* space*
|
|
588
626
|
}
|
|
589
627
|
|
|
590
628
|
LiquidDoc <: Helpers {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platformos/liquid-html-parser",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "Liquid HTML parser for platformOS",
|
|
5
5
|
"author": "platformOS",
|
|
6
6
|
"homepage": "https://github.com/Platform-OS/platformos-tools/tree/master/packages/liquid-html-parser#readme",
|