@intentius/chant 0.1.1 → 0.1.5

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 (128) hide show
  1. package/bin/chant +1 -10
  2. package/package.json +3 -5
  3. package/src/attrref.test.ts +1 -1
  4. package/src/bench.test.ts +1 -1
  5. package/src/build.test.ts +3 -5
  6. package/src/builder.test.ts +1 -1
  7. package/src/cli/commands/__fixtures__/init-lexicon-output/justfile +8 -8
  8. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +4 -4
  9. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/generate-cli.ts +1 -1
  10. package/src/cli/commands/__fixtures__/init-lexicon-output/src/plugin.ts +3 -3
  11. package/src/cli/commands/__fixtures__/init-lexicon-output/src/validate-cli.ts +1 -1
  12. package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +7 -7
  13. package/src/cli/commands/build.test.ts +1 -1
  14. package/src/cli/commands/diff.test.ts +1 -1
  15. package/src/cli/commands/doctor.test.ts +1 -1
  16. package/src/cli/commands/doctor.ts +7 -7
  17. package/src/cli/commands/import.test.ts +1 -1
  18. package/src/cli/commands/init-lexicon/templates/codegen.ts +1 -1
  19. package/src/cli/commands/init-lexicon/templates/plugin.ts +3 -3
  20. package/src/cli/commands/init-lexicon/templates/project.ts +13 -13
  21. package/src/cli/commands/init-lexicon/templates/tests.ts +4 -4
  22. package/src/cli/commands/init-lexicon.test.ts +2 -2
  23. package/src/cli/commands/init-lexicon.ts +1 -1
  24. package/src/cli/commands/init.test.ts +1 -1
  25. package/src/cli/commands/init.ts +1 -2
  26. package/src/cli/commands/lint.test.ts +3 -3
  27. package/src/cli/commands/list.test.ts +2 -2
  28. package/src/cli/commands/onboard.test.ts +33 -33
  29. package/src/cli/commands/onboard.ts +13 -13
  30. package/src/cli/commands/update.test.ts +1 -1
  31. package/src/cli/conflict-check.test.ts +7 -2
  32. package/src/cli/format.test.ts +1 -1
  33. package/src/cli/lsp/server.test.ts +8 -4
  34. package/src/cli/main.test.ts +1 -1
  35. package/src/cli/main.ts +6 -5
  36. package/src/cli/mcp/server.test.ts +1 -1
  37. package/src/cli/plugins.test.ts +1 -1
  38. package/src/cli/reporters/stylish.test.ts +1 -1
  39. package/src/cli/watch.test.ts +1 -1
  40. package/src/codegen/docs-interpolation.test.ts +3 -3
  41. package/src/codegen/docs-rules.test.ts +1 -1
  42. package/src/codegen/docs.ts +1 -1
  43. package/src/codegen/fetch.test.ts +1 -1
  44. package/src/codegen/generate-registry.test.ts +1 -1
  45. package/src/codegen/generate-runtime-index.test.ts +1 -1
  46. package/src/codegen/generate-typescript.test.ts +1 -1
  47. package/src/codegen/generate.test.ts +1 -1
  48. package/src/codegen/json-patch.test.ts +1 -1
  49. package/src/codegen/json-schema.test.ts +1 -1
  50. package/src/codegen/topo-sort.test.ts +1 -1
  51. package/src/codegen/typecheck.test.ts +1 -1
  52. package/src/codegen/typecheck.ts +18 -5
  53. package/src/codegen/validate.test.ts +1 -1
  54. package/src/composite.test.ts +17 -16
  55. package/src/composite.ts +5 -4
  56. package/src/config.test.ts +3 -3
  57. package/src/config.ts +0 -4
  58. package/src/declarable.test.ts +1 -1
  59. package/src/detectLexicon.test.ts +1 -1
  60. package/src/discovery/cache.test.ts +1 -1
  61. package/src/discovery/collect.test.ts +1 -1
  62. package/src/discovery/cycles.test.ts +1 -1
  63. package/src/discovery/files.test.ts +1 -1
  64. package/src/discovery/graph.test.ts +1 -1
  65. package/src/discovery/import.test.ts +4 -3
  66. package/src/discovery/index.test.ts +1 -1
  67. package/src/discovery/resolve.test.ts +1 -1
  68. package/src/errors.test.ts +1 -1
  69. package/src/import/base-parser.test.ts +1 -1
  70. package/src/import/ir-utils.test.ts +1 -1
  71. package/src/intrinsic-interpolation.test.ts +1 -1
  72. package/src/intrinsic.test.ts +1 -1
  73. package/src/lexicon-integrity.test.ts +2 -2
  74. package/src/lexicon-manifest.test.ts +1 -1
  75. package/src/lexicon-output.test.ts +1 -1
  76. package/src/lexicon-output.ts +5 -3
  77. package/src/lexicon-schema.test.ts +1 -1
  78. package/src/lint/config-overrides.test.ts +2 -2
  79. package/src/lint/config.test.ts +2 -2
  80. package/src/lint/config.ts +1 -1
  81. package/src/lint/declarative.test.ts +1 -1
  82. package/src/lint/discover.test.ts +1 -1
  83. package/src/lint/discover.ts +10 -0
  84. package/src/lint/engine.test.ts +1 -1
  85. package/src/lint/named-checks.test.ts +1 -1
  86. package/src/lint/parser.test.ts +2 -2
  87. package/src/lint/post-synth.test.ts +1 -1
  88. package/src/lint/rule-loader.test.ts +2 -2
  89. package/src/lint/rule-options.test.ts +2 -2
  90. package/src/lint/rule-registry.test.ts +1 -1
  91. package/src/lint/rule.test.ts +1 -1
  92. package/src/lint/rules/cor017-composite-name-match.test.ts +1 -1
  93. package/src/lint/rules/cor018-composite-prefer-lexicon-type.test.ts +1 -1
  94. package/src/lint/rules/declarable-naming-convention.test.ts +1 -1
  95. package/src/lint/rules/evl001-non-literal-expression.test.ts +1 -1
  96. package/src/lint/rules/evl002-control-flow-resource.test.ts +1 -1
  97. package/src/lint/rules/evl003-dynamic-property-access.test.ts +1 -1
  98. package/src/lint/rules/evl004-spread-non-const.test.ts +1 -1
  99. package/src/lint/rules/evl005-resource-block-body.test.ts +1 -1
  100. package/src/lint/rules/evl007-invalid-siblings.test.ts +1 -1
  101. package/src/lint/rules/evl009-composite-no-constant.test.ts +1 -1
  102. package/src/lint/rules/evl010-composite-no-transform.test.ts +1 -1
  103. package/src/lint/rules/export-required.test.ts +1 -1
  104. package/src/lint/rules/file-declarable-limit.test.ts +1 -1
  105. package/src/lint/rules/flat-declarations.test.ts +1 -1
  106. package/src/lint/rules/no-cyclic-declarable-ref.test.ts +1 -1
  107. package/src/lint/rules/no-redundant-type-import.test.ts +1 -1
  108. package/src/lint/rules/no-redundant-value-cast.test.ts +1 -1
  109. package/src/lint/rules/no-string-ref.test.ts +1 -1
  110. package/src/lint/rules/no-unused-declarable-import.test.ts +1 -1
  111. package/src/lint/rules/no-unused-declarable.test.ts +1 -1
  112. package/src/lint/rules/single-concern-file.test.ts +1 -1
  113. package/src/lint/selectors.test.ts +1 -1
  114. package/src/project-validation.test.ts +2 -2
  115. package/src/pseudo-parameter.test.ts +1 -1
  116. package/src/resource-attributes.test.ts +2 -2
  117. package/src/runtime-adapter.ts +13 -68
  118. package/src/runtime.ts +3 -3
  119. package/src/serializer-walker.test.ts +2 -1
  120. package/src/sort.test.ts +1 -1
  121. package/src/stack-output.ts +2 -2
  122. package/src/toml.test.ts +2 -2
  123. package/src/types.test.ts +1 -1
  124. package/src/utils.test.ts +1 -1
  125. package/src/utils.ts +2 -2
  126. package/src/validation.test.ts +1 -1
  127. package/src/yaml.test.ts +1 -1
  128. package/src/yaml.ts +4 -1
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import { flatDeclarationsRule } from "./flat-declarations";
4
4
  import type { LintContext } from "../rule";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import { noCyclicDeclarableRefRule } from "./no-cyclic-declarable-ref";
4
4
  import type { LintContext } from "../rule";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import { noRedundantTypeImportRule } from "./no-redundant-type-import";
4
4
  import type { LintContext } from "../rule";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import { noRedundantValueCastRule } from "./no-redundant-value-cast";
4
4
  import type { LintContext } from "../rule";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import { noStringRefRule } from "./no-string-ref";
4
4
  import type { LintContext } from "../rule";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import { noUnusedDeclarableImportRule } from "./no-unused-declarable-import";
4
4
  import type { LintContext } from "../rule";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import { noUnusedDeclarableRule } from "./no-unused-declarable";
4
4
  import type { LintContext } from "../rule";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import { singleConcernFileRule } from "./single-concern-file";
4
4
  import type { LintContext } from "../rule";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import * as ts from "typescript";
3
3
  import { resolveSelector, registerSelector, collectNodes } from "./selectors";
4
4
 
@@ -1,9 +1,9 @@
1
- import { describe, test, expect, beforeEach, afterEach } from "bun:test";
1
+ import { describe, test, expect, beforeEach, afterEach } from "vitest";
2
2
  import { validateProjectStructure } from "./project-validation";
3
3
  import { mkdirSync, writeFileSync, rmSync } from "fs";
4
4
  import { join } from "path";
5
5
 
6
- const TEST_DIR = join(import.meta.dir, "__test_project_validation__");
6
+ const TEST_DIR = join(import.meta.dirname, "__test_project_validation__");
7
7
 
8
8
  beforeEach(() => {
9
9
  mkdirSync(TEST_DIR, { recursive: true });
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "bun:test";
1
+ import { describe, expect, test } from "vitest";
2
2
  import { PseudoParameter, createPseudoParameters } from "./pseudo-parameter";
3
3
  import { INTRINSIC_MARKER } from "./intrinsic";
4
4
 
@@ -1,4 +1,4 @@
1
- import { describe, test, expect, spyOn } from "bun:test";
1
+ import { describe, test, expect, vi } from "vitest";
2
2
  import { resolveDependsOn } from "./resource-attributes";
3
3
  import { DECLARABLE_MARKER, type Declarable } from "./declarable";
4
4
 
@@ -55,7 +55,7 @@ describe("resolveDependsOn", () => {
55
55
  test("warns and skips Declarable not found in entityNames", () => {
56
56
  const bucket = mockDeclarable();
57
57
  const entityNames = new Map<Declarable, string>(); // bucket not registered
58
- const spy = spyOn(console, "warn").mockImplementation(() => {});
58
+ const spy = vi.spyOn(console, "warn").mockImplementation(() => {});
59
59
 
60
60
  const result = resolveDependsOn(bucket, entityNames, "MyResource");
61
61
  expect(result).toEqual([]);
@@ -1,9 +1,8 @@
1
1
  /**
2
- * Runtime adapter — abstracts Bun-specific APIs so chant can run on Bun or Node.js.
2
+ * Runtime adapter — abstracts child-process and filesystem APIs for chant.
3
3
  *
4
- * Auto-detects the host runtime and delegates to the appropriate implementation.
5
- * The `target` parameter (from config) controls what gets spawned (bun vs node/npx/npm),
6
- * not which adapter class is used.
4
+ * The `target` parameter (from config) controls what commands get spawned
5
+ * (node/npx/npm), not which adapter class is used.
7
6
  */
8
7
  import { dirname } from "path";
9
8
  import { fileURLToPath } from "url";
@@ -19,16 +18,16 @@ export interface SpawnResult {
19
18
  }
20
19
 
21
20
  export interface RuntimeCommands {
22
- /** Runtime binary: "bun" | "node" */
21
+ /** Runtime binary: "node" */
23
22
  runner: string;
24
- /** Package executor: "bunx" | "npx" */
23
+ /** Package executor: "npx" */
25
24
  exec: string;
26
- /** Pack command: ["bun", "pm", "pack"] | ["npm", "pack"] */
25
+ /** Pack command: ["npm", "pack"] */
27
26
  packCmd: string[];
28
27
  }
29
28
 
30
29
  export interface RuntimeAdapter {
31
- readonly name: "bun" | "node";
30
+ readonly name: "node";
32
31
  /** Hash content and return hex string */
33
32
  hash(content: string): string;
34
33
  /** Algorithm name recorded in integrity.json */
@@ -41,44 +40,6 @@ export interface RuntimeAdapter {
41
40
  readonly commands: RuntimeCommands;
42
41
  }
43
42
 
44
- // ── Bun adapter ──────────────────────────────────────────────────
45
-
46
- class BunRuntimeAdapter implements RuntimeAdapter {
47
- readonly name = "bun" as const;
48
- readonly hashAlgorithm = "xxhash64";
49
- readonly commands: RuntimeCommands;
50
-
51
- constructor(target: "bun" | "node") {
52
- this.commands =
53
- target === "node"
54
- ? { runner: "node", exec: "npx", packCmd: ["npm", "pack"] }
55
- : { runner: "bun", exec: "bunx", packCmd: ["bun", "pm", "pack"] };
56
- }
57
-
58
- hash(content: string): string {
59
- return Bun.hash(content).toString(16);
60
- }
61
-
62
- globMatch(pattern: string, filePath: string): boolean {
63
- const glob = new Bun.Glob(pattern);
64
- return glob.match(filePath);
65
- }
66
-
67
- async spawn(cmd: string[], opts?: { cwd?: string }): Promise<SpawnResult> {
68
- const proc = Bun.spawn(cmd, {
69
- cwd: opts?.cwd,
70
- stdout: "pipe",
71
- stderr: "pipe",
72
- });
73
- const [stdout, stderr] = await Promise.all([
74
- new Response(proc.stdout).text(),
75
- new Response(proc.stderr).text(),
76
- ]);
77
- const exitCode = await proc.exited;
78
- return { stdout, stderr, exitCode };
79
- }
80
- }
81
-
82
43
  // ── Node adapter ─────────────────────────────────────────────────
83
44
 
84
45
  class NodeRuntimeAdapter implements RuntimeAdapter {
@@ -86,11 +47,8 @@ class NodeRuntimeAdapter implements RuntimeAdapter {
86
47
  readonly hashAlgorithm = "sha256";
87
48
  readonly commands: RuntimeCommands;
88
49
 
89
- constructor(target: "bun" | "node") {
90
- this.commands =
91
- target === "bun"
92
- ? { runner: "bun", exec: "bunx", packCmd: ["bun", "pm", "pack"] }
93
- : { runner: "node", exec: "npx", packCmd: ["npm", "pack"] };
50
+ constructor() {
51
+ this.commands = { runner: "node", exec: "npx", packCmd: ["npm", "pack"] };
94
52
  }
95
53
 
96
54
  hash(content: string): string {
@@ -107,6 +65,7 @@ class NodeRuntimeAdapter implements RuntimeAdapter {
107
65
  resolve({
108
66
  stdout: stdout ?? "",
109
67
  stderr: stderr ?? "",
68
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
110
69
  exitCode: err ? (err as any).code ?? 1 : 0,
111
70
  });
112
71
  });
@@ -118,29 +77,16 @@ class NodeRuntimeAdapter implements RuntimeAdapter {
118
77
 
119
78
  let _runtime: RuntimeAdapter | undefined;
120
79
 
121
- /**
122
- * Detect whether we're running under Bun.
123
- */
124
- function isBun(): boolean {
125
- return typeof globalThis.Bun !== "undefined";
126
- }
127
-
128
80
  /**
129
81
  * Initialize the runtime adapter singleton.
130
- *
131
- * @param target - Which commands to spawn ("bun" or "node"). Defaults to auto-detect.
132
- * Controls the `commands` property, not which adapter class is used.
133
82
  */
134
- export function initRuntime(target?: "bun" | "node"): RuntimeAdapter {
135
- const resolvedTarget = target ?? (isBun() ? "bun" : "node");
136
- _runtime = isBun()
137
- ? new BunRuntimeAdapter(resolvedTarget)
138
- : new NodeRuntimeAdapter(resolvedTarget);
83
+ export function initRuntime(): RuntimeAdapter {
84
+ _runtime = new NodeRuntimeAdapter();
139
85
  return _runtime;
140
86
  }
141
87
 
142
88
  /**
143
- * Get the runtime adapter. Lazily initializes with auto-detection if not yet set.
89
+ * Get the runtime adapter. Lazily initializes if not yet set.
144
90
  */
145
91
  export function getRuntime(): RuntimeAdapter {
146
92
  if (!_runtime) {
@@ -151,7 +97,6 @@ export function getRuntime(): RuntimeAdapter {
151
97
 
152
98
  /**
153
99
  * Convert `import.meta.url` to a directory path.
154
- * Works on both Bun and Node (replaces Bun-only `import.meta.dir`).
155
100
  */
156
101
  export function moduleDir(importMetaUrl: string): string {
157
102
  return dirname(fileURLToPath(importMetaUrl));
package/src/runtime.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * lexicon, entityType, kind, and attribute references.
6
6
  */
7
7
 
8
- import { DECLARABLE_MARKER } from "./declarable";
8
+ import { DECLARABLE_MARKER, type Declarable } from "./declarable";
9
9
  import { AttrRef } from "./attrref";
10
10
 
11
11
  /**
@@ -22,7 +22,7 @@ export function createResource(
22
22
  type: string,
23
23
  lexicon: string,
24
24
  attrMap: Record<string, string>,
25
- ): new (props: Record<string, unknown>, attributes?: Record<string, unknown>) => Record<string, unknown> {
25
+ ): new (props: Record<string, unknown>, attributes?: Record<string, unknown>) => Declarable & Record<string, string> {
26
26
  const ResourceClass = function (this: Record<string, unknown>, props: Record<string, unknown>, attributes?: Record<string, unknown>) {
27
27
  Object.defineProperty(this, DECLARABLE_MARKER, { value: true, enumerable: false });
28
28
  Object.defineProperty(this, "lexicon", { value: lexicon, enumerable: false });
@@ -44,7 +44,7 @@ export function createResource(
44
44
  writable: false,
45
45
  });
46
46
  }
47
- } as unknown as new (props: Record<string, unknown>, attributes?: Record<string, unknown>) => Record<string, unknown>;
47
+ } as unknown as new (props: Record<string, unknown>, attributes?: Record<string, unknown>) => Declarable & Record<string, string>;
48
48
 
49
49
  // Set the constructor name for debugging
50
50
  Object.defineProperty(ResourceClass, "name", { value: type.split("::").pop() ?? type });
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { walkValue, type SerializerVisitor } from "./serializer-walker";
3
3
  import { DECLARABLE_MARKER, type Declarable } from "./declarable";
4
4
  import { INTRINSIC_MARKER } from "./intrinsic";
@@ -98,6 +98,7 @@ describe("walkValue", () => {
98
98
  const TestTable = createResource("Test::Table", "test", {});
99
99
  const resource = new TestTable({}) as unknown as Declarable;
100
100
  const names = new Map<Declarable, string>([[resource, "MyTable"]]);
101
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
101
102
  expect(walkValue((resource as any).Ref, names, mockVisitor)).toEqual({ __ref: "MyTable" });
102
103
  });
103
104
 
package/src/sort.test.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { topologicalSort } from "./sort";
3
3
  import { BuildError } from "./errors";
4
4
 
@@ -64,8 +64,8 @@ export function stackOutput(
64
64
  ): StackOutput {
65
65
  // Derive lexicon from the AttrRef's parent entity
66
66
  const parent = ref.parent.deref();
67
- const lexicon = parent && typeof (parent as any).lexicon === "string"
68
- ? (parent as any).lexicon
67
+ const lexicon = parent && typeof (parent as Record<string, unknown>).lexicon === "string"
68
+ ? (parent as Record<string, unknown>).lexicon as string
69
69
  : "unknown";
70
70
 
71
71
  const output: StackOutput = {
package/src/toml.test.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { emitTOML, parseTOML } from "./toml";
3
3
 
4
4
  describe("emitTOML", () => {
@@ -66,7 +66,7 @@ describe("emitTOML", () => {
66
66
 
67
67
  test("emits header comment", () => {
68
68
  const result = emitTOML({ name: "test" }, { header: "Generated by Chant" });
69
- expect(result).toStartWith("# Generated by Chant\n");
69
+ expect(result.startsWith("# Generated by Chant\n")).toBe(true);
70
70
  });
71
71
 
72
72
  test("respects key ordering", () => {
package/src/types.test.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { describe, test, expectTypeOf } from "bun:test";
1
+ import { describe, test, expectTypeOf } from "vitest";
2
2
  import type { Value, AllValues, PartialValues, RequiredProps } from "./types";
3
3
  import type { Intrinsic } from "./intrinsic";
4
4
 
package/src/utils.test.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import {
3
3
  LOGICAL_NAME_SYMBOL,
4
4
  getAttributes,
package/src/utils.ts CHANGED
@@ -19,8 +19,8 @@ export function isAttrRefLike(value: unknown): value is AttrRef {
19
19
  "parent" in value &&
20
20
  "attribute" in value &&
21
21
  "_setLogicalName" in value &&
22
- typeof (value as any).parent === "object" &&
23
- typeof (value as any).attribute === "string"
22
+ typeof (value as Record<string, unknown>).parent === "object" &&
23
+ typeof (value as Record<string, unknown>).attribute === "string"
24
24
  );
25
25
  }
26
26
 
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import {
3
3
  validate,
4
4
  type ValidationRule,
package/src/yaml.test.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "bun:test";
1
+ import { describe, expect, test } from "vitest";
2
2
  import { emitYAML, parseYAML, parseScalar } from "./yaml";
3
3
 
4
4
  // ---------------------------------------------------------------------------
package/src/yaml.ts CHANGED
@@ -188,7 +188,10 @@ export function parseYAMLLines(
188
188
  if (i + 1 < lines.length) {
189
189
  const nextLine = lines[i + 1];
190
190
  const nextIndent = nextLine.search(/\S/);
191
- if (nextIndent > indent && nextLine.trimStart().startsWith("- ")) {
191
+ if (nextLine.trimStart().startsWith("- ") && nextIndent >= indent) {
192
+ // Same-indent arrays are valid YAML (e.g. controller-gen output):
193
+ // versions:
194
+ // - name: v1
192
195
  const arr = parseYAMLArray(lines, i + 1, nextIndent);
193
196
  result[key] = arr.value;
194
197
  i = arr.endIndex;