@platformos/platformos-check-common 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.
Files changed (54) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/checks/index.d.ts +1 -1
  3. package/dist/checks/index.js +6 -2
  4. package/dist/checks/index.js.map +1 -1
  5. package/dist/checks/json-literal-quote-style/index.d.ts +2 -0
  6. package/dist/checks/json-literal-quote-style/index.js +42 -0
  7. package/dist/checks/json-literal-quote-style/index.js.map +1 -0
  8. package/dist/checks/liquid-html-syntax-error/checks/InvalidAssignSyntax.d.ts +21 -0
  9. package/dist/checks/liquid-html-syntax-error/checks/InvalidAssignSyntax.js +60 -0
  10. package/dist/checks/liquid-html-syntax-error/checks/InvalidAssignSyntax.js.map +1 -0
  11. package/dist/checks/liquid-html-syntax-error/checks/InvalidOutputPush.d.ts +17 -0
  12. package/dist/checks/liquid-html-syntax-error/checks/InvalidOutputPush.js +37 -0
  13. package/dist/checks/liquid-html-syntax-error/checks/InvalidOutputPush.js.map +1 -0
  14. package/dist/checks/liquid-html-syntax-error/checks/InvalidTagSyntax.js +1 -1
  15. package/dist/checks/liquid-html-syntax-error/index.js +17 -0
  16. package/dist/checks/liquid-html-syntax-error/index.js.map +1 -1
  17. package/dist/checks/partial-call-arguments/extract-undefined-variables.d.ts +14 -0
  18. package/dist/checks/partial-call-arguments/extract-undefined-variables.js +234 -0
  19. package/dist/checks/partial-call-arguments/extract-undefined-variables.js.map +1 -0
  20. package/dist/checks/partial-call-arguments/index.d.ts +2 -0
  21. package/dist/checks/partial-call-arguments/index.js +117 -0
  22. package/dist/checks/partial-call-arguments/index.js.map +1 -0
  23. package/dist/checks/unknown-property/index.js +22 -2
  24. package/dist/checks/unknown-property/index.js.map +1 -1
  25. package/dist/checks/valid-frontmatter/index.d.ts +2 -0
  26. package/dist/checks/valid-frontmatter/index.js +279 -0
  27. package/dist/checks/valid-frontmatter/index.js.map +1 -0
  28. package/dist/frontmatter/index.d.ts +1 -59
  29. package/dist/frontmatter/index.js +6 -298
  30. package/dist/frontmatter/index.js.map +1 -1
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/package.json +2 -2
  33. package/src/checks/index.ts +6 -2
  34. package/src/checks/json-literal-quote-style/index.spec.ts +129 -0
  35. package/src/checks/json-literal-quote-style/index.ts +45 -0
  36. package/src/checks/liquid-html-syntax-error/checks/InvalidAssignSyntax.spec.ts +422 -0
  37. package/src/checks/liquid-html-syntax-error/checks/InvalidAssignSyntax.ts +63 -0
  38. package/src/checks/liquid-html-syntax-error/checks/InvalidOutputPush.spec.ts +104 -0
  39. package/src/checks/liquid-html-syntax-error/checks/InvalidOutputPush.ts +39 -0
  40. package/src/checks/liquid-html-syntax-error/checks/InvalidTagSyntax.spec.ts +86 -2
  41. package/src/checks/liquid-html-syntax-error/checks/InvalidTagSyntax.ts +1 -1
  42. package/src/checks/liquid-html-syntax-error/index.ts +19 -0
  43. package/src/checks/partial-call-arguments/extract-undefined-variables.spec.ts +218 -0
  44. package/src/checks/{metadata-params → partial-call-arguments}/extract-undefined-variables.ts +31 -6
  45. package/src/checks/partial-call-arguments/index.spec.ts +436 -0
  46. package/src/checks/{metadata-params → partial-call-arguments}/index.ts +18 -11
  47. package/src/checks/undefined-object/index.spec.ts +101 -0
  48. package/src/checks/unknown-property/index.spec.ts +42 -0
  49. package/src/checks/unknown-property/index.ts +24 -2
  50. package/src/checks/valid-frontmatter/index.spec.ts +666 -0
  51. package/src/checks/valid-frontmatter/index.ts +344 -0
  52. package/src/frontmatter/index.ts +9 -344
  53. package/src/checks/metadata-params/extract-undefined-variables.spec.ts +0 -115
  54. package/src/checks/metadata-params/index.spec.ts +0 -257
@@ -401,6 +401,27 @@ query {
401
401
  expect(offenses[0].message).toEqual("Unknown property 'asd' on 'a'.");
402
402
  });
403
403
 
404
+ it('should handle hash literals with quoted string keys', async () => {
405
+ const sourceCode = `{% assign c = { "errors": {}, "valid": true } %}{{ c.valid }}{{ c.errors }}{{ c.missing }}`;
406
+ const offenses = await runLiquidCheck(UnknownProperty, sourceCode);
407
+ expect(offenses).toHaveLength(1);
408
+ expect(offenses[0].message).toEqual("Unknown property 'missing' on 'c'.");
409
+ });
410
+
411
+ it('should handle hash literals with mixed bare and quoted keys', async () => {
412
+ const sourceCode = `{% assign a = {x: 5, "y": 10} %}{{ a.x }}{{ a.y }}{{ a.z }}`;
413
+ const offenses = await runLiquidCheck(UnknownProperty, sourceCode);
414
+ expect(offenses).toHaveLength(1);
415
+ expect(offenses[0].message).toEqual("Unknown property 'z' on 'a'.");
416
+ });
417
+
418
+ it('should handle nested hash literals with quoted keys', async () => {
419
+ const sourceCode = `{% assign a = { "outer": { "inner": 1 } } %}{{ a.outer.inner }}{{ a.outer.missing }}`;
420
+ const offenses = await runLiquidCheck(UnknownProperty, sourceCode);
421
+ expect(offenses).toHaveLength(1);
422
+ expect(offenses[0].message).toEqual("Unknown property 'missing' on 'a.outer'.");
423
+ });
424
+
404
425
  it('should report unknown property on hash literal assigned via another variable', async () => {
405
426
  const sourceCode = `{% assign a = {a: 5} %}{% assign b = a.b %}`;
406
427
  const offenses = await runLiquidCheck(UnknownProperty, sourceCode);
@@ -409,6 +430,27 @@ query {
409
430
  });
410
431
  });
411
432
 
433
+ describe('function tag reassignment', () => {
434
+ it('should not report unknown property after function tag reassigns a variable', async () => {
435
+ const sourceCode = `{% assign object = { "valid": true, "id": id, "role": role } %}
436
+ {% function object = 'modules/core/commands/execute', object: object, mutation_name: 'some_mutation' %}
437
+ {% if object.errors == blank %}
438
+ {{ object.valid }}
439
+ {% endif %}`;
440
+ const offenses = await runLiquidCheck(UnknownProperty, sourceCode);
441
+ expect(offenses).toHaveLength(0);
442
+ });
443
+
444
+ it('should still report unknown property before function tag reassignment', async () => {
445
+ const sourceCode = `{% assign object = { "valid": true, "id": "123" } %}
446
+ {{ object.missing }}
447
+ {% function object = 'modules/core/commands/execute', object: object %}`;
448
+ const offenses = await runLiquidCheck(UnknownProperty, sourceCode);
449
+ expect(offenses).toHaveLength(1);
450
+ expect(offenses[0].message).toEqual("Unknown property 'missing' on 'object'.");
451
+ });
452
+ });
453
+
412
454
  describe('error message formatting', () => {
413
455
  it('should include variable name in error message', async () => {
414
456
  const sourceCode = `{% assign myVar = '{"a": 1}' | parse_json %}
@@ -11,6 +11,7 @@ import {
11
11
  TextNode,
12
12
  GraphQLMarkup,
13
13
  GraphQLInlineMarkup,
14
+ FunctionMarkup,
14
15
  HashAssignMarkup,
15
16
  JsonHashLiteral,
16
17
  JsonArrayLiteral,
@@ -263,6 +264,17 @@ export const UnknownProperty: LiquidCheckDefinition = {
263
264
  }
264
265
  }
265
266
 
267
+ // {% function object = 'partial_name', arg: value %}
268
+ // The function tag reassigns the variable to the return value of the partial,
269
+ // which has an unknown shape. Close any tracked shape so we don't false-positive.
270
+ if (isLiquidTagFunction(node)) {
271
+ const markup = node.markup;
272
+ const variableName = markup.name.name;
273
+ if (variableName) {
274
+ closeShapeRange(variableName, node.position.start);
275
+ }
276
+ }
277
+
266
278
  // {% hash_assign x["key"] = value %} or {% hash_assign x["a"]["b"] = value %}
267
279
  if (isLiquidTagHashAssign(node)) {
268
280
  const markup = node.markup;
@@ -531,6 +543,10 @@ function isLiquidTagGraphQL(
531
543
  return node.name === NamedTags.graphql && typeof node.markup !== 'string';
532
544
  }
533
545
 
546
+ function isLiquidTagFunction(node: LiquidTag): node is LiquidTag & { markup: FunctionMarkup } {
547
+ return node.name === NamedTags.function && typeof node.markup !== 'string';
548
+ }
549
+
534
550
  function isLiquidTagHashAssign(node: LiquidTag): node is LiquidTag & { markup: HashAssignMarkup } {
535
551
  return node.name === NamedTags.hash_assign && typeof node.markup !== 'string';
536
552
  }
@@ -578,10 +594,16 @@ function inferShapeFromLiteralNode(
578
594
  if (node.type === NodeTypes.JsonHashLiteral) {
579
595
  const properties = new Map<string, PropertyShape>();
580
596
  for (const entry of node.entries) {
581
- // Keys are VariableLookup nodes where the name is the key string
597
+ // Keys can be VariableLookup nodes (bare keys) or String nodes (quoted keys)
598
+ let keyName: string | undefined;
582
599
  if (entry.key.type === NodeTypes.VariableLookup && entry.key.name) {
600
+ keyName = entry.key.name;
601
+ } else if (entry.key.type === NodeTypes.String) {
602
+ keyName = entry.key.value;
603
+ }
604
+ if (keyName) {
583
605
  const valueShape = inferShapeFromExpressionNode(entry.value);
584
- properties.set(entry.key.name, valueShape ?? { kind: 'primitive' });
606
+ properties.set(keyName, valueShape ?? { kind: 'primitive' });
585
607
  }
586
608
  }
587
609
  return { kind: 'object', properties };