@intentius/chant 0.98.0 → 0.100.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/cli/commands/import.d.ts +20 -4
  2. package/dist/cli/commands/import.d.ts.map +1 -1
  3. package/dist/cli/commands/lint.d.ts.map +1 -1
  4. package/dist/deep-observation.d.ts.map +1 -1
  5. package/dist/import/embedded.d.ts +184 -0
  6. package/dist/import/embedded.d.ts.map +1 -0
  7. package/dist/import/generator.d.ts +13 -0
  8. package/dist/import/generator.d.ts.map +1 -1
  9. package/dist/import/parser.d.ts +15 -1
  10. package/dist/import/parser.d.ts.map +1 -1
  11. package/dist/lexicon.d.ts +19 -0
  12. package/dist/lexicon.d.ts.map +1 -1
  13. package/dist/lint/engine.d.ts +6 -1
  14. package/dist/lint/engine.d.ts.map +1 -1
  15. package/dist/lint/rule.d.ts +10 -0
  16. package/dist/lint/rule.d.ts.map +1 -1
  17. package/dist/lint/rules/file-declarable-limit.d.ts.map +1 -1
  18. package/dist/lint/rules/flat-declarations.d.ts.map +1 -1
  19. package/dist/lint/rules/no-unused-declarable.d.ts.map +1 -1
  20. package/dist/lint/rules/property-kind.d.ts +7 -0
  21. package/dist/lint/rules/property-kind.d.ts.map +1 -0
  22. package/dist/workspace/conformance/index.d.ts +9 -0
  23. package/dist/workspace/conformance/index.d.ts.map +1 -1
  24. package/dist/yaml.d.ts +28 -6
  25. package/dist/yaml.d.ts.map +1 -1
  26. package/package.json +1 -1
  27. package/src/cli/commands/import-layout.test.ts +142 -0
  28. package/src/cli/commands/import-no-parser.test.ts +1 -1
  29. package/src/cli/commands/import.test.ts +25 -0
  30. package/src/cli/commands/import.ts +158 -36
  31. package/src/cli/commands/lint.ts +21 -8
  32. package/src/deep-observation.test.ts +21 -0
  33. package/src/deep-observation.ts +9 -0
  34. package/src/import/embedded.test.ts +153 -0
  35. package/src/import/embedded.ts +376 -0
  36. package/src/import/generator.ts +14 -0
  37. package/src/import/parser.ts +17 -1
  38. package/src/lexicon.ts +21 -0
  39. package/src/lint/engine.ts +7 -0
  40. package/src/lint/rule.ts +10 -0
  41. package/src/lint/rules/file-declarable-limit.ts +11 -4
  42. package/src/lint/rules/flat-declarations.ts +6 -1
  43. package/src/lint/rules/no-unused-declarable.ts +59 -2
  44. package/src/lint/rules/property-kind.test.ts +99 -0
  45. package/src/lint/rules/property-kind.ts +56 -0
  46. package/src/workspace/conformance/index.mjs +1 -0
  47. package/src/workspace/conformance/index.ts +23 -1
  48. package/src/yaml.test.ts +192 -1
  49. package/src/yaml.ts +404 -250
package/src/yaml.test.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { describe, expect, test } from "vitest";
2
- import { emitYAML, parseYAML, parseYAMLDocument, parseScalar, splitYAMLDocuments } from "./yaml";
2
+ import { load as jsYamlLoad } from "js-yaml";
3
+ import { emitYAML, parseYAML, parseYAMLDocument, parseScalar, splitYAMLDocuments, YAMLParseError } from "./yaml";
3
4
 
4
5
  // ---------------------------------------------------------------------------
5
6
  // emitYAML
@@ -590,3 +591,193 @@ describe("splitYAMLDocuments", () => {
590
591
  expect(splitYAMLDocuments("a: 1\r\n--- # c\r\nb: 2\r\n")).toEqual(["a: 1", "b: 2\n"]);
591
592
  });
592
593
  });
594
+
595
+ // Blank, whitespace-only and comment lines inside a block, and other input the
596
+ // parser used to skip or hoist without a word (#2991). Each valid case is
597
+ // checked against js-yaml, so the expected value is what a full parser reads.
598
+ describe("parseYAML — blank lines inside blocks (#2991)", () => {
599
+ const same = (src: string): void => {
600
+ expect(parseYAMLDocument(src)).toEqual(jsYamlLoad(src));
601
+ };
602
+
603
+ test("a blank line between a key and its nested mapping (the reported bug)", () => {
604
+ expect(parseYAML("a:\n\n b: 1\nc: 2\n")).toEqual({ a: { b: 1 }, c: 2 });
605
+ });
606
+
607
+ test("a whitespace-only line between a key and its nested mapping", () => {
608
+ expect(parseYAML("a:\n \n b: 1\nc: 2\n")).toEqual({ a: { b: 1 }, c: 2 });
609
+ expect(parseYAML("a:\n\t\n b: 1\nc: 2\n")).toEqual({ a: { b: 1 }, c: 2 });
610
+ });
611
+
612
+ test("a comment at a lower column between a key and its nested mapping", () => {
613
+ same("a:\n# about b\n b: 1\nc: 2\n");
614
+ });
615
+
616
+ test("a blank line before the first item of a block sequence", () => {
617
+ // This one lost every key after the sequence, not just the sequence.
618
+ same("a:\n\n - 1\n - 2\nc: 2\n");
619
+ same("a:\n\n- 1\n- 2\nc: 2\n");
620
+ });
621
+
622
+ test("blank lines between block sequence items", () => {
623
+ same("a:\n - 1\n\n - \n\n - 3\nb: 2\n");
624
+ });
625
+
626
+ test("blank lines between the keys of a nested mapping", () => {
627
+ same("a:\n b: 1\n\n c:\n\n d: 2\n\n e: 3\nf: 4\n");
628
+ });
629
+
630
+ test("blank lines before nested blocks inside a sequence item", () => {
631
+ same("a:\n- name: x\n env:\n\n - n: 1\n meta:\n\n k: v\n\n last: 1\nc: 2\n");
632
+ same("a:\n- first:\n\n k: v\n second: 2\n");
633
+ });
634
+
635
+ test("a dash alone on its line takes the block below it", () => {
636
+ same("a:\n-\n x: 1\n y: 2\n-\n\n - 1\n-\n- z\n");
637
+ });
638
+
639
+ test("CRLF line endings, blank lines included", () => {
640
+ expect(parseYAML("a:\r\n\r\n b: 1\r\n c:\r\n \r\n - x\r\nd: 2\r\n")).toEqual({
641
+ a: { b: 1, c: ["x"] },
642
+ d: 2,
643
+ });
644
+ });
645
+
646
+ test("trailing whitespace on keys, items and blank lines", () => {
647
+ same("a: \n \n b: 1 \n c: \n\t\n d: 2\ne:\n - x \n - y: 1 \n z: 2\n");
648
+ });
649
+
650
+ test("a sequence item indented past `- ` keeps its keys together", () => {
651
+ same("- a: 1\n b: 2\n- c: 3\n");
652
+ });
653
+
654
+ test("the emitter's output still round-trips", () => {
655
+ const value = { a: { b: [{ c: 1, d: { e: "x" } }, "y"], f: null }, g: [[]] };
656
+ expect(parseYAML(emitYAML(value, 0).trimStart())).toEqual(value);
657
+ });
658
+ });
659
+
660
+ describe("parseYAML — scalars spanning lines (#2991)", () => {
661
+ const same = (src: string): void => {
662
+ expect(parseYAMLDocument(src)).toEqual(jsYamlLoad(src));
663
+ };
664
+
665
+ test("a plain scalar wrapped onto more lines, as go-yaml (Helm toYaml) wraps them", () => {
666
+ same("description: a long line that go-yaml\n wraps at eighty columns\n\n and a paragraph\nnext: 1\n");
667
+ });
668
+
669
+ test("a wrapped plain scalar as a sequence item and as an item's key", () => {
670
+ same("- long text\n continued\n- name: x\n help: more\n text\n after: 1\n");
671
+ });
672
+
673
+ test("a scalar on the line after its key", () => {
674
+ same("a:\n hello\n there\nb: 1\n");
675
+ });
676
+
677
+ test("a double-quoted scalar across lines, with a blank line and an escaped break", () => {
678
+ same('a: "one\n two\n\n three"\nb: "x\\\n y"\nc: 1\n');
679
+ });
680
+
681
+ test("a single-quoted scalar across lines", () => {
682
+ same("a: 'it''s\n here'\nb: 1\n");
683
+ });
684
+
685
+ test("an unterminated quoted scalar is an error", () => {
686
+ expect(() => parseYAML('a: "abc\nb: 1\n')).toThrow(YAMLParseError);
687
+ });
688
+ });
689
+
690
+ describe("parseYAML — quoted keys (#2991)", () => {
691
+ test("a quoted key holding a colon is read, not skipped", () => {
692
+ expect(parseYAML('"a:b": 1\nc: 2\n')).toEqual({ "a:b": 1, c: 2 });
693
+ });
694
+
695
+ test("quotes are not part of the key", () => {
696
+ expect(parseYAMLDocument("- \"a\": \"b\"\n 'c:d': 2\n")).toEqual([{ a: "b", "c:d": 2 }]);
697
+ });
698
+ });
699
+
700
+ describe("parseYAML — lines it cannot place are errors, not drops (#2991)", () => {
701
+ const throwsAt = (src: string, line: number): void => {
702
+ let error: unknown;
703
+ try {
704
+ parseYAML(src);
705
+ } catch (err) {
706
+ error = err;
707
+ }
708
+ expect(error).toBeInstanceOf(YAMLParseError);
709
+ expect((error as YAMLParseError).line).toBe(line);
710
+ };
711
+
712
+ test("a key indented under a scalar value", () => {
713
+ // Used to read as { a: 1, b: 2, c: 3 }.
714
+ throwsAt("a: 1\n b: 2\nc: 3\n", 2);
715
+ });
716
+
717
+ test("a key indented past its siblings inside a sequence item", () => {
718
+ throwsAt("items:\n- name: x\n image: y\n stray: z\n", 4);
719
+ });
720
+
721
+ test("a line that is neither a key nor an item", () => {
722
+ throwsAt("a: 1\njust text\nb: 2\n", 2);
723
+ });
724
+
725
+ test("a dedent to a column no mapping is at", () => {
726
+ throwsAt(" a: 1\nb: 2\n", 2);
727
+ });
728
+
729
+ test("a tag before a nested block names the construct", () => {
730
+ expect(() => parseYAML("a: !Thing\n b: 1\n")).toThrow(/the tag "!Thing"/);
731
+ });
732
+
733
+ test("an alias with no anchor before it", () => {
734
+ throwsAt("a: *nowhere\n", 1);
735
+ });
736
+
737
+ test("document markers are still skipped, as before", () => {
738
+ expect(parseYAML("---\na: 1\n...\n")).toEqual({ a: 1 });
739
+ });
740
+
741
+ test("a top-level list still reads as an empty mapping through parseYAML", () => {
742
+ expect(parseYAML("- a\n- b\n")).toEqual({});
743
+ });
744
+ });
745
+
746
+ // GitLab CI templates and Alertmanager configs anchor a block and merge it
747
+ // elsewhere. Before #2991 the anchored block was hoisted into its parent and
748
+ // the alias read as the string "*name".
749
+ describe("parseYAML — anchors, aliases and merge keys (#2991)", () => {
750
+ const same = (src: string): void => {
751
+ expect(parseYAMLDocument(src)).toEqual(jsYamlLoad(src));
752
+ };
753
+
754
+ test("an anchored mapping merged into jobs, a GitLab CI template", () => {
755
+ same(
756
+ ".test-template: &test-defaults\n stage: test\n before_script:\n - npm ci\n\n" +
757
+ "unit-test:\n <<: *test-defaults\n script:\n - npm test\n" +
758
+ "lint:\n stage: lint\n <<: *test-defaults\n",
759
+ );
760
+ });
761
+
762
+ test("an anchored sequence item merged into the next, an Alertmanager receiver", () => {
763
+ same("slack_configs:\n - &slack\n channel: '#db-alerts'\n send_resolved: true\n - <<: *slack\n channel: '#db-oncall'\n");
764
+ });
765
+
766
+ test("anchored scalars and sequences, and aliases to them", () => {
767
+ same("a: &v 1\nb: *v\nc: &list\n - x\n - y\nd: *list\ne:\n - *v\n - *list\n");
768
+ });
769
+
770
+ test("several anchors merged at once; the first listed wins", () => {
771
+ same("a: &a\n x: 1\n y: 1\nb: &b\n y: 2\n z: 2\nc:\n <<: [*a, *b]\n z: 3\n");
772
+ });
773
+
774
+ test("an alias is a copy, not shared with its anchor", () => {
775
+ const doc = parseYAML("a: &a\n x: 1\nb: *a\n") as { a: { x: number }; b: { x: number } };
776
+ doc.b.x = 2;
777
+ expect(doc.a.x).toBe(1);
778
+ });
779
+
780
+ test("a merge key needs a mapping", () => {
781
+ expect(() => parseYAML("a: &v 1\nb:\n <<: *v\n")).toThrow(YAMLParseError);
782
+ });
783
+ });