@platformos/liquid-html-parser 0.0.8 → 0.0.9

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.
@@ -62,6 +62,7 @@ export declare enum ConcreteNodeTypes {
62
62
  Comparison = "Comparison",
63
63
  Condition = "Condition",
64
64
  AssignMarkup = "AssignMarkup",
65
+ AssignPushRhs = "AssignPushRhs",
65
66
  HashAssignMarkup = "HashAssignMarkup",
66
67
  ContentForMarkup = "ContentForMarkup",
67
68
  CycleMarkup = "CycleMarkup",
@@ -262,11 +263,15 @@ export interface ConcreteLiquidTagLiquid extends ConcreteLiquidTagNode<NamedTags
262
263
  export type ConcreteLiquidLiquidTagNode = ConcreteLiquidTagOpen | ConcreteLiquidTagClose | ConcreteLiquidTag | ConcreteLiquidRawTag;
263
264
  export interface ConcreteLiquidTagAssign extends ConcreteLiquidTagNode<NamedTags.assign, ConcreteLiquidTagAssignMarkup> {
264
265
  }
266
+ export interface ConcreteLiquidTagAssignPushRhs extends ConcreteBasicNode<ConcreteNodeTypes.AssignPushRhs> {
267
+ pushSource: ConcreteLiquidVariable;
268
+ pushValue: ConcreteLiquidVariable;
269
+ }
265
270
  export interface ConcreteLiquidTagAssignMarkup extends ConcreteBasicNode<ConcreteNodeTypes.AssignMarkup> {
266
271
  name: string;
267
272
  target: ConcreteLiquidVariableLookup;
268
273
  operator: string;
269
- value: ConcreteLiquidVariable;
274
+ value: ConcreteLiquidVariable | ConcreteLiquidTagAssignPushRhs;
270
275
  }
271
276
  export interface ConcreteLiquidTagHashAssign extends ConcreteLiquidTagNode<NamedTags.hash_assign, ConcreteLiquidTagHashAssignMarkup> {
272
277
  }
@@ -416,7 +421,7 @@ export interface ConcreteLiquidFilter extends ConcreteBasicNode<ConcreteNodeType
416
421
  export type ConcreteLiquidArgument = ConcreteLiquidExpression | ConcreteLiquidNamedArgument;
417
422
  export interface ConcreteLiquidNamedArgument extends ConcreteBasicNode<ConcreteNodeTypes.NamedArgument> {
418
423
  name: string;
419
- value: ConcreteLiquidExpression;
424
+ value: ConcreteLiquidExpression | ConcreteLiquidVariable;
420
425
  }
421
426
  export type ConcreteLiquidExpression = ConcreteStringLiteral | ConcreteNumberLiteral | ConcreteLiquidLiteral | ConcreteLiquidRange | ConcreteLiquidVariableLookup | ConcreteJsonHashLiteral | ConcreteJsonArrayLiteral;
422
427
  export type ConcreteComplexLiquidExpression = ConcreteLiquidBooleanExpression | ConcreteLiquidExpression;
@@ -452,7 +457,7 @@ export interface ConcreteJsonKeyValuePair extends ConcreteBasicNode<ConcreteNode
452
457
  export interface ConcreteJsonArrayLiteral extends ConcreteBasicNode<ConcreteNodeTypes.JsonArrayLiteral> {
453
458
  elements: ConcreteJsonValue[];
454
459
  }
455
- export type ConcreteJsonValue = ConcreteJsonHashLiteral | ConcreteJsonArrayLiteral | ConcreteLiquidExpression;
460
+ export type ConcreteJsonValue = ConcreteJsonHashLiteral | ConcreteJsonArrayLiteral | ConcreteLiquidVariable | ConcreteLiquidExpression;
456
461
  export type ConcreteHtmlNode = ConcreteHtmlDoctype | ConcreteHtmlComment | ConcreteHtmlRawTag | ConcreteHtmlVoidElement | ConcreteHtmlSelfClosingElement | ConcreteHtmlTagOpen | ConcreteHtmlTagClose;
457
462
  export interface ConcreteTextNode extends ConcreteBasicNode<ConcreteNodeTypes.TextNode> {
458
463
  value: string;
@@ -70,6 +70,7 @@ var ConcreteNodeTypes;
70
70
  ConcreteNodeTypes["Comparison"] = "Comparison";
71
71
  ConcreteNodeTypes["Condition"] = "Condition";
72
72
  ConcreteNodeTypes["AssignMarkup"] = "AssignMarkup";
73
+ ConcreteNodeTypes["AssignPushRhs"] = "AssignPushRhs";
73
74
  ConcreteNodeTypes["HashAssignMarkup"] = "HashAssignMarkup";
74
75
  ConcreteNodeTypes["ContentForMarkup"] = "ContentForMarkup";
75
76
  ConcreteNodeTypes["CycleMarkup"] = "CycleMarkup";
@@ -365,6 +366,26 @@ function toCST(source /* the original file */, grammars, grammar, cstMappings, m
365
366
  source,
366
367
  },
367
368
  assignOperator: (node) => node.sourceString,
369
+ liquidAssignValue: 0,
370
+ liquidAssignPushExpr: {
371
+ type: ConcreteNodeTypes.AssignPushRhs,
372
+ // tokens: [pushSource, space*, "<<", space*, pushValue]
373
+ pushSource: 0,
374
+ pushValue: 4,
375
+ locStart,
376
+ locEnd,
377
+ source,
378
+ },
379
+ liquidAssignPushSource: {
380
+ type: ConcreteNodeTypes.LiquidVariable,
381
+ expression: 0,
382
+ filters: 1,
383
+ // No &delim lookahead at end (unlike liquidAssignVariable), so last token is space*
384
+ rawSource: (tokens) => source.slice(locStart(tokens), tokens[tokens.length - 1].source.endIdx).trimEnd(),
385
+ locStart,
386
+ locEnd,
387
+ source,
388
+ },
368
389
  liquidAssignVariable: {
369
390
  type: ConcreteNodeTypes.LiquidVariable,
370
391
  expression: 0,
@@ -407,6 +428,16 @@ function toCST(source /* the original file */, grammars, grammar, cstMappings, m
407
428
  source,
408
429
  },
409
430
  liquidJsonValue: 0,
431
+ liquidJsonItemVariable: {
432
+ type: ConcreteNodeTypes.LiquidVariable,
433
+ expression: 0,
434
+ filters: 1,
435
+ // No &delim lookahead at end (unlike liquidVariable), so last token is space*
436
+ rawSource: (tokens) => source.slice(locStart(tokens), tokens[tokens.length - 1].source.endIdx).trimEnd(),
437
+ locStart,
438
+ locEnd,
439
+ source,
440
+ },
410
441
  liquidJsonSep: 1,
411
442
  liquidTagHashAssignMarkup: {
412
443
  type: ConcreteNodeTypes.HashAssignMarkup,
@@ -637,6 +668,23 @@ function toCST(source /* the original file */, grammars, grammar, cstMappings, m
637
668
  }
638
669
  },
639
670
  },
671
+ // Same as liquidFilter but without trailing comma — used inside JSON values to avoid
672
+ // consuming JSON entry separator commas as trailing filter argument commas.
673
+ liquidJsonFilter: {
674
+ type: ConcreteNodeTypes.LiquidFilter,
675
+ name: 3,
676
+ locStart,
677
+ locEnd,
678
+ source,
679
+ args(nodes) {
680
+ if (nodes[7].sourceString === '') {
681
+ return [];
682
+ }
683
+ else {
684
+ return nodes[7].toAST(this.args.mapping);
685
+ }
686
+ },
687
+ },
640
688
  filterArguments: 0,
641
689
  arguments: 0,
642
690
  complexArguments: function (completeParams, _space1, _comma, _space2, incompleteParam) {
@@ -647,6 +695,8 @@ function toCST(source /* the original file */, grammars, grammar, cstMappings, m
647
695
  },
648
696
  simpleArgument: 0,
649
697
  tagArguments: 0,
698
+ graphqlArguments: 0,
699
+ graphqlRenderArguments: 1,
650
700
  positionalArgument: 0,
651
701
  namedArgument: {
652
702
  type: ConcreteNodeTypes.NamedArgument,
@@ -656,6 +706,23 @@ function toCST(source /* the original file */, grammars, grammar, cstMappings, m
656
706
  locEnd,
657
707
  source,
658
708
  },
709
+ graphqlNamedArgument: {
710
+ type: ConcreteNodeTypes.NamedArgument,
711
+ name: 0,
712
+ value: 4,
713
+ locStart,
714
+ locEnd,
715
+ source,
716
+ },
717
+ graphqlNamedArgumentValue: {
718
+ type: ConcreteNodeTypes.LiquidVariable,
719
+ expression: 0,
720
+ filters: 1,
721
+ rawSource: (tokens) => source.slice(locStart(tokens), locEnd(tokens)),
722
+ locStart,
723
+ locEnd,
724
+ source,
725
+ },
659
726
  liquidBooleanExpression(initialCondition, subsequentConditions) {
660
727
  const initialConditionAst = initialCondition.toAST(this.args.mapping);
661
728
  const subsequentConditionAsts = subsequentConditions.toAST(this.args.mapping);
@@ -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 | 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;
38
+ export type LiquidHtmlNode = DocumentNode | YAMLFrontmatter | LiquidNode | HtmlDoctype | HtmlNode | AttributeNode | LiquidVariable | ComplexLiquidExpression | LiquidFilter | LiquidNamedArgument | AssignMarkup | AssignPushRhs | 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,8 +143,15 @@ 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;
146
+ /** the value of the variable that is being assigned, or a push expression */
147
+ value: LiquidVariable | AssignPushRhs;
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;
148
155
  }
149
156
  export interface LiquidTagHashAssign extends LiquidTagNode<NamedTags.hash_assign, HashAssignMarkup> {
150
157
  }
@@ -498,12 +505,15 @@ export interface LiquidFilter extends ASTNode<NodeTypes.LiquidFilter> {
498
505
  }
499
506
  /** Represents the union type of positional and named arguments */
500
507
  export type LiquidArgument = LiquidExpression | LiquidNamedArgument;
501
- /** Named arguments are the ones used in kwargs, such as `name: value` */
508
+ /** Named arguments are the ones used in kwargs, such as `name: value` or `name: value | filter` */
502
509
  export interface LiquidNamedArgument extends ASTNode<NodeTypes.NamedArgument> {
503
510
  /** name: value */
504
511
  name: string;
505
- /** name: value */
506
- value: LiquidExpression;
512
+ /**
513
+ * For regular tags (render, function, for, etc.): a plain LiquidExpression (no filters).
514
+ * For graphql tags: a LiquidVariable which may include filters (e.g. `name: val | fetch: "key"`).
515
+ */
516
+ value: LiquidExpression | LiquidVariable;
507
517
  }
508
518
  export interface LiquidBooleanExpression extends ASTNode<NodeTypes.BooleanExpression> {
509
519
  condition: LiquidConditionalExpression;
@@ -553,11 +563,11 @@ export interface JsonHashLiteral extends ASTNode<NodeTypes.JsonHashLiteral> {
553
563
  /** Represents a key-value pair in a JSON hash literal */
554
564
  export interface JsonKeyValuePair extends ASTNode<NodeTypes.JsonKeyValuePair> {
555
565
  key: LiquidExpression;
556
- value: LiquidExpression;
566
+ value: LiquidExpression | LiquidVariable;
557
567
  }
558
568
  /** Represents a JSON array literal [el1, el2, ...] */
559
569
  export interface JsonArrayLiteral extends ASTNode<NodeTypes.JsonArrayLiteral> {
560
- elements: LiquidExpression[];
570
+ elements: (LiquidExpression | LiquidVariable)[];
561
571
  }
562
572
  /** The union type of all HTML nodes */
563
573
  export type HtmlNode = HtmlComment | HtmlElement | HtmlDanglingMarkerClose | HtmlVoidElement | HtmlSelfClosingElement | HtmlRawNode;
@@ -898,12 +898,24 @@ function toUnnamedLiquidBranch(parentNode) {
898
898
  };
899
899
  }
900
900
  function toAssignMarkup(node) {
901
+ const value = node.value.type === stage_1_cst_1.ConcreteNodeTypes.AssignPushRhs
902
+ ? toAssignPushRhs(node.value)
903
+ : toLiquidVariable(node.value);
901
904
  return {
902
905
  type: types_1.NodeTypes.AssignMarkup,
903
906
  name: node.name,
904
907
  lookups: node.target.lookups.map(toExpression),
905
908
  operator: node.operator,
906
- value: toLiquidVariable(node.value),
909
+ value,
910
+ position: position(node),
911
+ source: node.source,
912
+ };
913
+ }
914
+ function toAssignPushRhs(node) {
915
+ return {
916
+ type: types_1.NodeTypes.AssignPushRhs,
917
+ pushSource: toLiquidVariable(node.pushSource),
918
+ pushValue: toLiquidVariable(node.pushValue),
907
919
  position: position(node),
908
920
  source: node.source,
909
921
  };
@@ -1316,7 +1328,7 @@ function toExpression(node) {
1316
1328
  case stage_1_cst_1.ConcreteNodeTypes.JsonArrayLiteral: {
1317
1329
  return {
1318
1330
  type: types_1.NodeTypes.JsonArrayLiteral,
1319
- elements: node.elements.map(toExpression),
1331
+ elements: node.elements.map(toJsonValue),
1320
1332
  position: position(node),
1321
1333
  source: node.source,
1322
1334
  };
@@ -1326,11 +1338,17 @@ function toExpression(node) {
1326
1338
  }
1327
1339
  }
1328
1340
  }
1341
+ function toJsonValue(node) {
1342
+ if (node.type === stage_1_cst_1.ConcreteNodeTypes.LiquidVariable) {
1343
+ return toLiquidVariable(node);
1344
+ }
1345
+ return toExpression(node);
1346
+ }
1329
1347
  function toJsonKeyValuePair(node) {
1330
1348
  return {
1331
1349
  type: types_1.NodeTypes.JsonKeyValuePair,
1332
1350
  key: toExpression(node.key),
1333
- value: toExpression(node.value),
1351
+ value: toJsonValue(node.value),
1334
1352
  position: position(node),
1335
1353
  source: node.source,
1336
1354
  };
@@ -1358,7 +1376,9 @@ function toNamedArgument(node) {
1358
1376
  return {
1359
1377
  type: types_1.NodeTypes.NamedArgument,
1360
1378
  name: node.name,
1361
- value: toExpression(node.value),
1379
+ value: node.value.type === stage_1_cst_1.ConcreteNodeTypes.LiquidVariable
1380
+ ? toLiquidVariable(node.value)
1381
+ : toExpression(node.value),
1362
1382
  position: position(node),
1363
1383
  source: node.source,
1364
1384
  };
package/dist/types.d.ts CHANGED
@@ -35,6 +35,7 @@ export declare enum NodeTypes {
35
35
  Comparison = "Comparison",
36
36
  LogicalExpression = "LogicalExpression",
37
37
  AssignMarkup = "AssignMarkup",
38
+ AssignPushRhs = "AssignPushRhs",
38
39
  HashAssignMarkup = "HashAssignMarkup",
39
40
  ContentForMarkup = "ContentForMarkup",
40
41
  CycleMarkup = "CycleMarkup",
package/dist/types.js CHANGED
@@ -33,6 +33,7 @@ var NodeTypes;
33
33
  NodeTypes["Comparison"] = "Comparison";
34
34
  NodeTypes["LogicalExpression"] = "LogicalExpression";
35
35
  NodeTypes["AssignMarkup"] = "AssignMarkup";
36
+ NodeTypes["AssignPushRhs"] = "AssignPushRhs";
36
37
  NodeTypes["HashAssignMarkup"] = "HashAssignMarkup";
37
38
  NodeTypes["ContentForMarkup"] = "ContentForMarkup";
38
39
  NodeTypes["CycleMarkup"] = "CycleMarkup";
@@ -106,7 +106,7 @@ Liquid <: Helpers {
106
106
 
107
107
  liquidTagOpenGraphQL = liquidTagOpenRule<"graphql", liquidTagGraphQLInlineMarkup>
108
108
  // Use negative lookahead to exclude file-based syntax (with "=")
109
- liquidTagGraphQLInlineMarkup = variableSegment ~(space* "=") renderArguments
109
+ liquidTagGraphQLInlineMarkup = variableSegment ~(space* "=") graphqlRenderArguments
110
110
 
111
111
  liquidTagOpen =
112
112
  | liquidTagOpenStrict
@@ -126,12 +126,21 @@ Liquid <: Helpers {
126
126
  liquidTagEchoMarkup = liquidVariable<delimTag>
127
127
 
128
128
  liquidTagAssign = liquidTagRule<"assign", liquidTagAssignMarkup>
129
- liquidTagAssignMarkup = assignTarget<delimTag> space* assignOperator space* liquidAssignVariable<delimTag>
129
+ liquidTagAssignMarkup = assignTarget<delimTag> space* assignOperator space* liquidAssignValue<delimTag>
130
130
 
131
131
  // Assign-specific sub-rules
132
132
  assignTarget<delim> = variableSegment lookup<delim>*
133
133
  assignOperator = "<<" | "="
134
134
 
135
+ // The RHS of an assign: either an explicit push expression (source << value) or a regular value
136
+ liquidAssignValue<delim> = liquidAssignPushExpr<delim> | liquidAssignVariable<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*
143
+
135
144
  // Assign variable: like liquidVariable but expression allows JSON literals
136
145
  liquidAssignVariable<delim> = liquidAssignExpression<delim> liquidFilter<delim>* space* &delim
137
146
  liquidAssignExpression<delim> =
@@ -151,7 +160,16 @@ Liquid <: Helpers {
151
160
  liquidJsonValue<delim> =
152
161
  | liquidJsonHashLiteral<delim>
153
162
  | liquidJsonArrayLiteral<delim>
163
+ | liquidJsonItemVariable<delim>
154
164
  | liquidExpression<delim>
165
+ // Like liquidVariable but without &delim lookahead, so it works inside JSON structures.
166
+ // Requires at least one filter (liquidJsonFilter+) so plain expressions fall through to liquidExpression.
167
+ // Uses liquidJsonFilter (no trailing comma) instead of liquidFilter to avoid consuming the
168
+ // JSON entry separator comma (e.g. the "," in { "a": x | filter: arg, "b": y }).
169
+ liquidJsonItemVariable<delim> = liquidComplexExpression<delim> liquidJsonFilter<delim>+ space*
170
+ // Like liquidFilter but without the trailing (space* ",")? so commas between JSON entries
171
+ // are not consumed as trailing filter argument commas.
172
+ liquidJsonFilter<delim> = space* "|" space* identifier (space* ":" space* arguments<delim>)?
155
173
  liquidJsonSep = space* "," space*
156
174
 
157
175
  liquidTagHashAssign = liquidTagRule<"hash_assign", liquidTagHashAssignMarkup>
@@ -186,17 +204,17 @@ Liquid <: Helpers {
186
204
  liquidTagInclude = liquidTagRule<"include", liquidTagRenderMarkup>
187
205
  liquidTagRender = liquidTagRule<"render", liquidTagRenderMarkup>
188
206
  liquidTagRenderMarkup =
189
- snippetExpression renderVariableExpression? renderAliasExpression? renderArguments
207
+ partialExpression renderVariableExpression? renderAliasExpression? renderArguments
190
208
 
191
209
  liquidTagFunction = liquidTagRule<"function", liquidTagFunctionMarkup>
192
- liquidTagFunctionMarkup = variableSegment space* "=" space* snippetExpression renderArguments
210
+ liquidTagFunctionMarkup = variableSegment space* "=" space* partialExpression renderArguments
193
211
 
194
212
  liquidTagGraphQL = liquidTagRule<"graphql", liquidTagGraphQLMarkup>
195
- liquidTagGraphQLMarkup = variableSegment space* "=" space* snippetExpression renderArguments
213
+ liquidTagGraphQLMarkup = variableSegment space* "=" space* partialExpression graphqlRenderArguments
196
214
 
197
215
  // platformos simple tags
198
216
  liquidTagBackground = liquidTagRule<"background", liquidTagBackgroundMarkup>
199
- liquidTagBackgroundMarkup = variableSegment space* "=" space* snippetExpression renderArguments
217
+ liquidTagBackgroundMarkup = variableSegment space* "=" space* partialExpression renderArguments
200
218
 
201
219
  liquidTagOpenBackground = liquidTagOpenRule<"background", liquidTagBackgroundInlineMarkup>
202
220
  // Use negative lookahead to exclude file-based syntax (with "=")
@@ -243,7 +261,7 @@ Liquid <: Helpers {
243
261
  liquidTagRedirectToMarkup = liquidExpression<delimTag> renderArguments
244
262
 
245
263
  liquidTagIncludeForm = liquidTagRule<"include_form", liquidTagIncludeFormMarkup>
246
- liquidTagIncludeFormMarkup = snippetExpression renderArguments
264
+ liquidTagIncludeFormMarkup = partialExpression renderArguments
247
265
 
248
266
  liquidTagSpamProtection = liquidTagRule<"spam_protection", liquidTagSpamProtectionMarkup>
249
267
  liquidTagSpamProtectionMarkup = liquidExpression<delimTag> renderArguments
@@ -260,7 +278,6 @@ Liquid <: Helpers {
260
278
 
261
279
  renderArguments = (argumentSeparatorOptionalComma tagArguments) (space* ",")? space*
262
280
  completionModeRenderArguments = (argumentSeparatorOptionalComma tagArguments) (space* ",")? space* (argumentSeparator? liquidVariableLookup<delimTag> space*)?
263
- snippetExpression = liquidString<delimTag> | variableSegmentAsLookup
264
281
  partialExpression = liquidString<delimTag> | variableSegmentAsLookup
265
282
  renderVariableExpression = space+ ("for" | "with") space+ liquidExpression<delimTag>
266
283
  renderAliasExpression = space+ "as" space+ variableSegment
@@ -322,7 +339,7 @@ Liquid <: Helpers {
322
339
  | ">="
323
340
  | "<="
324
341
  | ">"
325
- | "<")
342
+ | "<" ~"<")
326
343
  | ("contains" ~identifier)
327
344
 
328
345
  liquidDrop = "{{" "-"? space* liquidDropCases "-"? "}}"
@@ -420,6 +437,10 @@ Liquid <: Helpers {
420
437
  positionalArgument<delim> = liquidExpression<delim> ~(space* ":")
421
438
  namedArgument<delim> = variableSegment space* ":" space* liquidExpression<delim>
422
439
  tagArguments = listOf<namedArgument<delimTag>, argumentSeparatorOptionalComma>
440
+ graphqlArguments = listOf<graphqlNamedArgument, argumentSeparatorOptionalComma>
441
+ graphqlNamedArgument = variableSegment space* ":" space* graphqlNamedArgumentValue
442
+ graphqlNamedArgumentValue = liquidExpression<delimTag> liquidFilter<delimTag>*
443
+ graphqlRenderArguments = (argumentSeparatorOptionalComma graphqlArguments) (space* ",")? space*
423
444
  filterArguments<delim> =
424
445
  | complexArguments<delim>
425
446
  | simpleArgument<delim>
@@ -709,7 +730,7 @@ StrictLiquidHTML <: LiquidHTML {
709
730
  WithPlaceholderLiquid <: Liquid {
710
731
  liquidFilter<delim> := space* "|" space* identifier (space* ":" space* filterArguments<delim> (space* ",")?)?
711
732
  liquidTagRenderMarkup :=
712
- snippetExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
733
+ partialExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
713
734
  liquidTagName := (letter | "█") (alnum | "_")*
714
735
  variableSegment := (letter | "_" | "█") (identifierCharacter | "█")*
715
736
  liquidDoc :=
@@ -721,7 +742,7 @@ WithPlaceholderLiquid <: Liquid {
721
742
  WithPlaceholderLiquidStatement <: LiquidStatement {
722
743
  liquidFilter<delim> := space* "|" space* identifier (space* ":" space* filterArguments<delim> (space* ",")?)?
723
744
  liquidTagRenderMarkup :=
724
- snippetExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
745
+ partialExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
725
746
  liquidTagName := (letter | "█") (alnum | "_")*
726
747
  variableSegment := (letter | "_" | "█") (identifierCharacter | "█")*
727
748
  liquidDoc :=
@@ -733,7 +754,7 @@ WithPlaceholderLiquidStatement <: LiquidStatement {
733
754
  WithPlaceholderLiquidHTML <: LiquidHTML {
734
755
  liquidFilter<delim> := space* "|" space* identifier (space* ":" space* filterArguments<delim> (space* ",")?)?
735
756
  liquidTagRenderMarkup :=
736
- snippetExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
757
+ partialExpression renderVariableExpression? renderAliasExpression? completionModeRenderArguments
737
758
  liquidTagName := (letter | "█") (alnum | "_")*
738
759
  variableSegment := (letter | "_" | "█") (identifierCharacter | "█")*
739
760
  leadingTagNameTextNode := (letter | "█") (alnum | "-" | ":" | "█")*
@@ -106,7 +106,7 @@ Liquid <: Helpers {
106
106
 
107
107
  liquidTagOpenGraphQL = liquidTagOpenRule<"graphql", liquidTagGraphQLInlineMarkup>
108
108
  // Use negative lookahead to exclude file-based syntax (with "=")
109
- liquidTagGraphQLInlineMarkup = variableSegment ~(space* "=") renderArguments
109
+ liquidTagGraphQLInlineMarkup = variableSegment ~(space* "=") graphqlRenderArguments
110
110
 
111
111
  liquidTagOpen =
112
112
  | liquidTagOpenStrict
@@ -126,12 +126,21 @@ Liquid <: Helpers {
126
126
  liquidTagEchoMarkup = liquidVariable<delimTag>
127
127
 
128
128
  liquidTagAssign = liquidTagRule<"assign", liquidTagAssignMarkup>
129
- liquidTagAssignMarkup = assignTarget<delimTag> space* assignOperator space* liquidAssignVariable<delimTag>
129
+ liquidTagAssignMarkup = assignTarget<delimTag> space* assignOperator space* liquidAssignValue<delimTag>
130
130
 
131
131
  // Assign-specific sub-rules
132
132
  assignTarget<delim> = variableSegment lookup<delim>*
133
133
  assignOperator = "<<" | "="
134
134
 
135
+ // The RHS of an assign: either an explicit push expression (source << value) or a regular value
136
+ liquidAssignValue<delim> = liquidAssignPushExpr<delim> | liquidAssignVariable<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*
143
+
135
144
  // Assign variable: like liquidVariable but expression allows JSON literals
136
145
  liquidAssignVariable<delim> = liquidAssignExpression<delim> liquidFilter<delim>* space* &delim
137
146
  liquidAssignExpression<delim> =
@@ -151,7 +160,16 @@ Liquid <: Helpers {
151
160
  liquidJsonValue<delim> =
152
161
  | liquidJsonHashLiteral<delim>
153
162
  | liquidJsonArrayLiteral<delim>
163
+ | liquidJsonItemVariable<delim>
154
164
  | liquidExpression<delim>
165
+ // Like liquidVariable but without &delim lookahead, so it works inside JSON structures.
166
+ // Requires at least one filter (liquidJsonFilter+) so plain expressions fall through to liquidExpression.
167
+ // Uses liquidJsonFilter (no trailing comma) instead of liquidFilter to avoid consuming the
168
+ // JSON entry separator comma (e.g. the "," in { "a": x | filter: arg, "b": y }).
169
+ liquidJsonItemVariable<delim> = liquidComplexExpression<delim> liquidJsonFilter<delim>+ space*
170
+ // Like liquidFilter but without the trailing (space* ",")? so commas between JSON entries
171
+ // are not consumed as trailing filter argument commas.
172
+ liquidJsonFilter<delim> = space* "|" space* identifier (space* ":" space* arguments<delim>)?
155
173
  liquidJsonSep = space* "," space*
156
174
 
157
175
  liquidTagHashAssign = liquidTagRule<"hash_assign", liquidTagHashAssignMarkup>
@@ -192,7 +210,7 @@ Liquid <: Helpers {
192
210
  liquidTagFunctionMarkup = variableSegment space* "=" space* snippetExpression renderArguments
193
211
 
194
212
  liquidTagGraphQL = liquidTagRule<"graphql", liquidTagGraphQLMarkup>
195
- liquidTagGraphQLMarkup = variableSegment space* "=" space* snippetExpression renderArguments
213
+ liquidTagGraphQLMarkup = variableSegment space* "=" space* snippetExpression graphqlRenderArguments
196
214
 
197
215
  // platformos simple tags
198
216
  liquidTagBackground = liquidTagRule<"background", liquidTagBackgroundMarkup>
@@ -322,7 +340,7 @@ Liquid <: Helpers {
322
340
  | ">="
323
341
  | "<="
324
342
  | ">"
325
- | "<")
343
+ | "<" ~"<")
326
344
  | ("contains" ~identifier)
327
345
 
328
346
  liquidDrop = "{{" "-"? space* liquidDropCases "-"? "}}"
@@ -420,6 +438,10 @@ Liquid <: Helpers {
420
438
  positionalArgument<delim> = liquidExpression<delim> ~(space* ":")
421
439
  namedArgument<delim> = variableSegment space* ":" space* liquidExpression<delim>
422
440
  tagArguments = listOf<namedArgument<delimTag>, argumentSeparatorOptionalComma>
441
+ graphqlArguments = listOf<graphqlNamedArgument, argumentSeparatorOptionalComma>
442
+ graphqlNamedArgument = variableSegment space* ":" space* graphqlNamedArgumentValue
443
+ graphqlNamedArgumentValue = liquidExpression<delimTag> liquidFilter<delimTag>*
444
+ graphqlRenderArguments = (argumentSeparatorOptionalComma graphqlArguments) (space* ",")? space*
423
445
  filterArguments<delim> =
424
446
  | complexArguments<delim>
425
447
  | simpleArgument<delim>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platformos/liquid-html-parser",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
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",