@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
package/bin/chant CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/bin/sh
2
- # Cross-runtime CLI wrapper. Tries bun first, falls back to npx tsx.
3
2
  set -e
4
3
 
5
4
  # Resolve symlinks to find the real script location
@@ -7,17 +6,9 @@ SELF="$0"
7
6
  while [ -L "$SELF" ]; do
8
7
  DIR="$(cd "$(dirname "$SELF")" && pwd)"
9
8
  SELF="$(readlink "$SELF")"
10
- # Handle relative symlink targets
11
9
  case "$SELF" in /*) ;; *) SELF="$DIR/$SELF" ;; esac
12
10
  done
13
11
  SCRIPT_DIR="$(cd "$(dirname "$SELF")" && pwd)"
14
12
  MAIN_TS="$SCRIPT_DIR/../src/cli/main.ts"
15
13
 
16
- if command -v bun >/dev/null 2>&1; then
17
- exec bun "$MAIN_TS" "$@"
18
- elif command -v npx >/dev/null 2>&1; then
19
- exec npx tsx "$MAIN_TS" "$@"
20
- else
21
- echo "error: chant requires Bun (https://bun.sh) or Node.js (https://nodejs.org)" >&2
22
- exit 1
23
- fi
14
+ exec npx tsx "$MAIN_TS" "$@"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.1.1",
4
- "description": "Declarative infrastructure-as-code toolkit — TypeScript on Bun",
3
+ "version": "0.1.5",
4
+ "description": "Declarative infrastructure-as-code toolkit — TypeScript on Node.js",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
7
7
  "repository": {
@@ -41,10 +41,8 @@
41
41
  "dependencies": {
42
42
  "fflate": "^0.8.2",
43
43
  "picomatch": "^4.0.3",
44
+ "tsx": "^4.0.0",
44
45
  "typescript": "^5.5.0",
45
46
  "zod": "^4.3.6"
46
- },
47
- "optionalDependencies": {
48
- "tsx": "^4.0.0"
49
47
  }
50
48
  }
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { AttrRef } from "./attrref";
3
3
  import { INTRINSIC_MARKER, isIntrinsic } from "./intrinsic";
4
4
 
package/src/bench.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 { withTestDir } from "@intentius/chant-test-utils";
3
3
  import { writeFile, mkdir } from "node:fs/promises";
4
4
  import { join } from "node:path";
package/src/build.test.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { describe, test, expect, beforeEach, afterEach } from "bun:test";
2
- import { build, partitionByLexicon, detectCrossLexiconRefs } from "./build";
1
+ import { describe, test, expect, beforeEach, afterEach } from "vitest";
2
+ import { build, partitionByLexicon, detectCrossLexiconRefs, collectLexiconOutputs } from "./build";
3
3
  import { output } from "./lexicon-output";
4
4
  import { AttrRef } from "./attrref";
5
5
  import { INTRINSIC_MARKER } from "./intrinsic";
@@ -354,7 +354,6 @@ describe("detectCrossLexiconRefs", () => {
354
354
  expect(autoDetected[0].outputName).toBe("dataBucket_Arn");
355
355
 
356
356
  // But when collecting explicit outputs, the explicit one is found
357
- const { collectLexiconOutputs } = require("./build");
358
357
  const explicitOutputs = collectLexiconOutputs(entities);
359
358
  expect(explicitOutputs).toHaveLength(1);
360
359
  expect(explicitOutputs[0].outputName).toBe("MyCustomArnName");
@@ -369,7 +368,7 @@ describe("detectCrossLexiconRefs", () => {
369
368
  ...autoDetected.filter((auto) => {
370
369
  const autoParent = auto._sourceParent?.deref();
371
370
  return !explicitRefs.some(
372
- (e: { parent: object | undefined; attribute: string }) =>
371
+ (e: { parent: object | undefined; attribute: string | null }) =>
373
372
  e.parent === autoParent && e.attribute === auto.sourceAttribute
374
373
  );
375
374
  }),
@@ -422,7 +421,6 @@ describe("detectCrossLexiconRefs", () => {
422
421
  ["myUrl", intrinsicOutput as unknown as Declarable],
423
422
  ]);
424
423
 
425
- const { collectLexiconOutputs } = require("./build");
426
424
  const collected = collectLexiconOutputs(entities);
427
425
  expect(collected).toHaveLength(1);
428
426
  expect(collected[0].outputName).toBe("MyUrl");
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { Builder } from "./builder";
3
3
  import type { Declarable } from "./declarable";
4
4
  import { DECLARABLE_MARKER } from "./declarable";
@@ -4,23 +4,23 @@ default:
4
4
 
5
5
  # Generate types and metadata from upstream schemas
6
6
  generate:
7
- bun run src/codegen/generate-cli.ts
7
+ npx tsx src/codegen/generate-cli.ts
8
8
 
9
9
  # Validate generated artifacts
10
10
  validate:
11
- bun run src/validate-cli.ts
11
+ npx tsx src/validate-cli.ts
12
12
 
13
13
  # Generate docs site, install deps, and start dev server
14
14
  docs:
15
- bun run src/codegen/docs-cli.ts
16
- bun install --cwd docs
17
- bun --cwd docs dev
15
+ npx tsx src/codegen/docs-cli.ts
16
+ npm install --prefix docs
17
+ npm run --prefix docs dev
18
18
 
19
19
  # Build docs site for production
20
20
  docs-build:
21
- bun run src/codegen/docs-cli.ts
22
- bun install --cwd docs
23
- bun --cwd docs build
21
+ npx tsx src/codegen/docs-cli.ts
22
+ npm install --prefix docs
23
+ npm run --prefix docs build
24
24
 
25
25
  # Package the lexicon (generate + validate)
26
26
  package: generate validate
@@ -15,10 +15,10 @@
15
15
  "./types": "./dist/types/index.d.ts"
16
16
  },
17
17
  "scripts": {
18
- "generate": "bun run src/codegen/generate-cli.ts",
19
- "validate": "bun run src/validate-cli.ts",
20
- "docs": "bun src/codegen/docs-cli.ts",
21
- "prepack": "bun run generate && bun run validate"
18
+ "generate": "npx tsx src/codegen/generate-cli.ts",
19
+ "validate": "npx tsx src/validate-cli.ts",
20
+ "docs": "npx tsx src/codegen/docs-cli.ts",
21
+ "prepack": "npm run generate && npm run validate"
22
22
  },
23
23
  "dependencies": {
24
24
  "@intentius/chant": "workspace:*"
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env tsx
2
2
  import { generate, writeGeneratedFiles } from "./generate";
3
3
  import { dirname } from "path";
4
4
  import { fileURLToPath } from "url";
@@ -4,6 +4,9 @@ import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
4
4
  import type { CompletionContext, CompletionItem, HoverContext, HoverInfo } from "@intentius/chant/lsp/types";
5
5
  import type { McpToolContribution, McpResourceContribution } from "@intentius/chant/mcp/types";
6
6
  import { fixtureSerializer } from "./serializer";
7
+ import { rules } from "./lint/rules";
8
+ import { completions } from "./lsp/completions";
9
+ import { hover } from "./lsp/hover";
7
10
 
8
11
  /**
9
12
  * fixture lexicon plugin.
@@ -49,7 +52,6 @@ export const fixturePlugin: LexiconPlugin = {
49
52
  // ── Optional extensions ────────────────────────────────────
50
53
 
51
54
  lintRules() {
52
- const { rules } = require("./lint/rules");
53
55
  return rules;
54
56
  },
55
57
 
@@ -74,12 +76,10 @@ export const fixturePlugin: LexiconPlugin = {
74
76
  },
75
77
 
76
78
  completionProvider(ctx: CompletionContext) {
77
- const { completions } = require("./lsp/completions");
78
79
  return completions(ctx);
79
80
  },
80
81
 
81
82
  hoverProvider(ctx: HoverContext) {
82
- const { hover } = require("./lsp/hover");
83
83
  return hover(ctx);
84
84
  },
85
85
 
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env tsx
2
2
  import { validate } from "./validate";
3
3
 
4
4
  await validate({ verbose: true });
@@ -1,6 +1,6 @@
1
- // Bun Snapshot v1, https://bun.sh/docs/test/snapshots
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
- exports[`init-lexicon fixture snapshot fixture generate.ts matches snapshot 1`] = `
3
+ exports[`init-lexicon fixture snapshot > fixture generate.ts matches snapshot 1`] = `
4
4
  "import { generatePipeline, writeGeneratedArtifacts } from "@intentius/chant/codegen/generate";
5
5
  import type { GenerateResult } from "@intentius/chant/codegen/generate";
6
6
  import { dirname } from "path";
@@ -78,7 +78,7 @@ export function writeGeneratedFiles(result: GenerateResult, pkgDir?: string): vo
78
78
  "
79
79
  `;
80
80
 
81
- exports[`init-lexicon fixture snapshot fixture package.ts matches snapshot 1`] = `
81
+ exports[`init-lexicon fixture snapshot > fixture package.ts matches snapshot 1`] = `
82
82
  "import { packagePipeline } from "@intentius/chant/codegen/package";
83
83
  import type { PackagePipelineConfig } from "@intentius/chant/codegen/package";
84
84
  import { generate } from "./generate";
@@ -107,13 +107,16 @@ export async function packageLexicon(options?: { verbose?: boolean; force?: bool
107
107
  "
108
108
  `;
109
109
 
110
- exports[`init-lexicon fixture snapshot fixture plugin.ts matches snapshot 1`] = `
110
+ exports[`init-lexicon fixture snapshot > fixture plugin.ts matches snapshot 1`] = `
111
111
  "import type { LexiconPlugin, SkillDefinition, IntrinsicDef } from "@intentius/chant/lexicon";
112
112
  import type { LintRule } from "@intentius/chant/lint/rule";
113
113
  import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
114
114
  import type { CompletionContext, CompletionItem, HoverContext, HoverInfo } from "@intentius/chant/lsp/types";
115
115
  import type { McpToolContribution, McpResourceContribution } from "@intentius/chant/mcp/types";
116
116
  import { fixtureSerializer } from "./serializer";
117
+ import { rules } from "./lint/rules";
118
+ import { completions } from "./lsp/completions";
119
+ import { hover } from "./lsp/hover";
117
120
 
118
121
  /**
119
122
  * fixture lexicon plugin.
@@ -159,7 +162,6 @@ export const fixturePlugin: LexiconPlugin = {
159
162
  // ── Optional extensions ────────────────────────────────────
160
163
 
161
164
  lintRules() {
162
- const { rules } = require("./lint/rules");
163
165
  return rules;
164
166
  },
165
167
 
@@ -184,12 +186,10 @@ export const fixturePlugin: LexiconPlugin = {
184
186
  },
185
187
 
186
188
  completionProvider(ctx: CompletionContext) {
187
- const { completions } = require("./lsp/completions");
188
189
  return completions(ctx);
189
190
  },
190
191
 
191
192
  hoverProvider(ctx: HoverContext) {
192
- const { hover } = require("./lsp/hover");
193
193
  return hover(ctx);
194
194
  },
195
195
 
@@ -1,4 +1,4 @@
1
- import { describe, test, expect, beforeEach, afterEach } from "bun:test";
1
+ import { describe, test, expect, beforeEach, afterEach } from "vitest";
2
2
  import { buildCommand, type BuildOptions } from "./build";
3
3
  import type { Serializer } from "../../serializer";
4
4
  import { mkdir, rm, writeFile } from "node:fs/promises";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect, beforeEach, afterEach } from "bun:test";
1
+ import { describe, test, expect, beforeEach, afterEach } from "vitest";
2
2
  import { diffCommand, type DiffOptions } from "./diff";
3
3
  import type { Serializer } from "../../serializer";
4
4
  import { mkdir, rm, writeFile } from "node:fs/promises";
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { doctorCommand } from "./doctor";
3
3
  import { withTestDir } from "@intentius/chant-test-utils";
4
4
  import { writeFileSync, mkdirSync } from "fs";
@@ -21,13 +21,13 @@ export async function doctorCommand(path: string): Promise<DoctorReport> {
21
21
  const checks: DoctorCheck[] = [];
22
22
  const projectPath = path || ".";
23
23
 
24
- // Check 0: Bun is installed
24
+ // Check 0: Node.js is installed
25
25
  try {
26
- const bunVersion = execSync("bun --version", { encoding: "utf-8" }).trim();
27
- checks.push({ name: "bun-installed", status: "pass", message: `v${bunVersion}` });
26
+ const nodeVersion = execSync("node --version", { encoding: "utf-8" }).trim();
27
+ checks.push({ name: "node-installed", status: "pass", message: nodeVersion });
28
28
  } catch (e) {
29
- debug("bun version check failed:", e);
30
- checks.push({ name: "bun-installed", status: "fail", message: "Bun is not installed — see https://bun.sh" });
29
+ debug("node version check failed:", e);
30
+ checks.push({ name: "node-installed", status: "fail", message: "Node.js is not installed — see https://nodejs.org" });
31
31
  }
32
32
 
33
33
  // Check 1: Config exists and parses
@@ -89,7 +89,7 @@ export async function doctorCommand(path: string): Promise<DoctorReport> {
89
89
  }
90
90
 
91
91
  // Check 4-6: Per-lexicon checks
92
- const lexicons = (config as any)?.lexicons as string[] | undefined;
92
+ const lexicons = config?.lexicons as string[] | undefined;
93
93
  if (lexicons && Array.isArray(lexicons)) {
94
94
  for (const lex of lexicons) {
95
95
  const lexDir = join(projectPath, ".chant", "types", `lexicon-${lex}`);
@@ -157,7 +157,7 @@ export async function doctorCommand(path: string): Promise<DoctorReport> {
157
157
  const cleaned = raw.replace(/\/\/.*$/gm, "");
158
158
  const tsconfig = JSON.parse(cleaned);
159
159
  if (tsconfig.compilerOptions?.paths) {
160
- checks.push({ name: "tsconfig-paths", status: "warn", message: "tsconfig.json has compilerOptions.paths — these break runtime module resolution (bun and tsx follow them). Remove the paths block." });
160
+ checks.push({ name: "tsconfig-paths", status: "warn", message: "tsconfig.json has compilerOptions.paths — these break runtime module resolution (tsx follows them). Remove the paths block." });
161
161
  } else {
162
162
  checks.push({ name: "tsconfig-paths", status: "pass" });
163
163
  }
@@ -1,4 +1,4 @@
1
- import { describe, test, expect, beforeEach, afterEach } from "bun:test";
1
+ import { describe, test, expect, beforeEach, afterEach } from "vitest";
2
2
  import { importCommand, type ImportOptions } from "./import";
3
3
  import { mkdir, rm, writeFile } from "node:fs/promises";
4
4
  import { existsSync, readFileSync } from "node:fs";
@@ -81,7 +81,7 @@ export function writeGeneratedFiles(result: GenerateResult, pkgDir?: string): vo
81
81
  }
82
82
 
83
83
  export function generateCodegenGenerateCliTs(): string {
84
- return `#!/usr/bin/env bun
84
+ return `#!/usr/bin/env tsx
85
85
  import { generate, writeGeneratedFiles } from "./generate";
86
86
  import { dirname } from "path";
87
87
  import { fileURLToPath } from "url";
@@ -9,6 +9,9 @@ import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
9
9
  import type { CompletionContext, CompletionItem, HoverContext, HoverInfo } from "@intentius/chant/lsp/types";
10
10
  import type { McpToolContribution, McpResourceContribution } from "@intentius/chant/mcp/types";
11
11
  import { ${names.serializerVarName} } from "./serializer";
12
+ import { rules } from "./lint/rules";
13
+ import { completions } from "./lsp/completions";
14
+ import { hover } from "./lsp/hover";
12
15
 
13
16
  /**
14
17
  * ${name} lexicon plugin.
@@ -54,7 +57,6 @@ export const ${names.pluginVarName}: LexiconPlugin = {
54
57
  // ── Optional extensions ────────────────────────────────────
55
58
 
56
59
  lintRules() {
57
- const { rules } = require("./lint/rules");
58
60
  return rules;
59
61
  },
60
62
 
@@ -79,12 +81,10 @@ export const ${names.pluginVarName}: LexiconPlugin = {
79
81
  },
80
82
 
81
83
  completionProvider(ctx: CompletionContext) {
82
- const { completions } = require("./lsp/completions");
83
84
  return completions(ctx);
84
85
  },
85
86
 
86
87
  hoverProvider(ctx: HoverContext) {
87
- const { hover } = require("./lsp/hover");
88
88
  return hover(ctx);
89
89
  },
90
90
 
@@ -17,10 +17,10 @@ export function generatePackageJson(name: string, names: { packageName: string }
17
17
  "./types": "./dist/types/index.d.ts",
18
18
  },
19
19
  scripts: {
20
- generate: "bun run src/codegen/generate-cli.ts",
21
- validate: "bun run src/validate-cli.ts",
22
- docs: "bun src/codegen/docs-cli.ts",
23
- prepack: "bun run generate && bun run validate",
20
+ generate: "npx tsx src/codegen/generate-cli.ts",
21
+ validate: "npx tsx src/validate-cli.ts",
22
+ docs: "npx tsx src/codegen/docs-cli.ts",
23
+ prepack: "npm run generate && npm run validate",
24
24
  },
25
25
  dependencies: {
26
26
  "@intentius/chant": "workspace:*",
@@ -53,23 +53,23 @@ default:
53
53
 
54
54
  # Generate types and metadata from upstream schemas
55
55
  generate:
56
- bun run src/codegen/generate-cli.ts
56
+ npx tsx src/codegen/generate-cli.ts
57
57
 
58
58
  # Validate generated artifacts
59
59
  validate:
60
- bun run src/validate-cli.ts
60
+ npx tsx src/validate-cli.ts
61
61
 
62
62
  # Generate docs site, install deps, and start dev server
63
63
  docs:
64
- bun run src/codegen/docs-cli.ts
65
- bun install --cwd docs
66
- bun --cwd docs dev
64
+ npx tsx src/codegen/docs-cli.ts
65
+ npm install --prefix docs
66
+ npm run --prefix docs dev
67
67
 
68
68
  # Build docs site for production
69
69
  docs-build:
70
- bun run src/codegen/docs-cli.ts
71
- bun install --cwd docs
72
- bun --cwd docs build
70
+ npx tsx src/codegen/docs-cli.ts
71
+ npm install --prefix docs
72
+ npm run --prefix docs build
73
73
 
74
74
  # Package the lexicon (generate + validate)
75
75
  package: generate validate
@@ -174,7 +174,7 @@ export async function validate(opts?: { basePath?: string }): Promise<ValidateRe
174
174
  }
175
175
 
176
176
  export function generateValidateCliTs(): string {
177
- return `#!/usr/bin/env bun
177
+ return `#!/usr/bin/env tsx
178
178
  import { validate } from "./validate";
179
179
 
180
180
  await validate({ verbose: true });
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  export function generatePluginTestTs(name: string, names: { pluginVarName: string }): string {
6
- return `import { describe, expect, it } from "bun:test";
6
+ return `import { describe, expect, it } from "vitest";
7
7
  import { ${names.pluginVarName} } from "./plugin";
8
8
  import { isLexiconPlugin } from "@intentius/chant/lexicon";
9
9
 
@@ -24,7 +24,7 @@ describe("${name} plugin", () => {
24
24
  }
25
25
 
26
26
  export function generateSerializerTestTs(name: string, names: { serializerVarName: string }): string {
27
- return `import { describe, expect, it } from "bun:test";
27
+ return `import { describe, expect, it } from "vitest";
28
28
  import { ${names.serializerVarName} } from "./serializer";
29
29
 
30
30
  describe("${name} serializer", () => {
@@ -42,7 +42,7 @@ describe("${name} serializer", () => {
42
42
  }
43
43
 
44
44
  export function generateCompletionsTestTs(): string {
45
- return `import { describe, expect, it } from "bun:test";
45
+ return `import { describe, expect, it } from "vitest";
46
46
  import { completions } from "./completions";
47
47
 
48
48
  describe("LSP completions", () => {
@@ -56,7 +56,7 @@ describe("LSP completions", () => {
56
56
  }
57
57
 
58
58
  export function generateHoverTestTs(): string {
59
- return `import { describe, expect, it } from "bun:test";
59
+ return `import { describe, expect, it } from "vitest";
60
60
  import { hover } from "./hover";
61
61
 
62
62
  describe("LSP hover", () => {
@@ -1,4 +1,4 @@
1
- import { describe, test, expect, beforeEach, afterEach } from "bun:test";
1
+ import { describe, test, expect, beforeEach, afterEach } from "vitest";
2
2
  import { existsSync, readFileSync, mkdirSync, writeFileSync, rmSync, readdirSync } from "fs";
3
3
  import { join, dirname } from "path";
4
4
  import { tmpdir } from "os";
@@ -250,7 +250,7 @@ describe("init-lexicon fixture snapshot", () => {
250
250
  path: FIXTURE_DIR,
251
251
  });
252
252
 
253
- // Remove generated .test.ts files so bun test won't try to run them as tests
253
+ // Remove generated .test.ts files so they won't be discovered by the test runner
254
254
  for (const f of [
255
255
  "src/plugin.test.ts",
256
256
  "src/serializer.test.ts",
@@ -216,7 +216,7 @@ export async function printInitLexiconResult(result: InitLexiconResult): Promise
216
216
  console.log("");
217
217
  console.log("Next steps:");
218
218
  console.log(" 1. cd into the lexicon directory");
219
- console.log(" 2. bun install");
219
+ console.log(" 2. npm install");
220
220
  console.log(" 3. Edit src/spec/fetch.ts — point at your upstream schema source");
221
221
  console.log(" 4. Edit src/spec/parse.ts — parse your schema format");
222
222
  console.log(" 5. just generate — generate types from spec");
@@ -1,4 +1,4 @@
1
- import { describe, test, expect } from "bun:test";
1
+ import { describe, test, expect } from "vitest";
2
2
  import { initCommand, type InitOptions } from "./init";
3
3
  import { withTestDir } from "@intentius/chant-test-utils";
4
4
  import { writeFile } from "node:fs/promises";
@@ -51,11 +51,10 @@ export interface InitResult {
51
51
 
52
52
  /**
53
53
  * Detect whether the user's project uses bun or npm.
54
- * Checks for lock files first, then falls back to runtime detection.
54
+ * Checks for lock files.
55
55
  */
56
56
  function detectPackageManager(dir?: string): "bun" | "npm" {
57
57
  if (dir && (existsSync(join(dir, "bun.lockb")) || existsSync(join(dir, "bun.lock")))) return "bun";
58
- if (typeof globalThis.Bun !== "undefined") return "bun";
59
58
  return "npm";
60
59
  }
61
60
 
@@ -1,4 +1,4 @@
1
- import { describe, test, expect, beforeEach, afterEach } from "bun:test";
1
+ import { describe, test, expect, beforeEach, afterEach } from "vitest";
2
2
  import { lintCommand, isLintRule, loadPluginRules, type LintOptions } from "./lint";
3
3
  import { mkdir, rm, writeFile } from "node:fs/promises";
4
4
  import { join, resolve } from "node:path";
@@ -218,7 +218,7 @@ describe("isLintRule", () => {
218
218
 
219
219
  describe("loadPluginRules", () => {
220
220
  test("loads rules from a plugin file", async () => {
221
- const fixtureDir = resolve(import.meta.dir, "__fixtures__");
221
+ const fixtureDir = resolve(import.meta.dirname, "__fixtures__");
222
222
  const rules = await loadPluginRules(["./sample-rule.ts"], fixtureDir);
223
223
 
224
224
  expect(rules.size).toBe(1);
@@ -230,7 +230,7 @@ describe("loadPluginRules", () => {
230
230
  });
231
231
 
232
232
  test("silently skips non-LintRule exports", async () => {
233
- const fixtureDir = resolve(import.meta.dir, "__fixtures__");
233
+ const fixtureDir = resolve(import.meta.dirname, "__fixtures__");
234
234
  const rules = await loadPluginRules(["./sample-rule.ts"], fixtureDir);
235
235
 
236
236
  // sample-rule.ts exports notARule too, which should be skipped
@@ -1,4 +1,4 @@
1
- import { describe, test, expect, beforeEach, afterEach } from "bun:test";
1
+ import { describe, test, expect, beforeEach, afterEach } from "vitest";
2
2
  import { listCommand, type ListOptions } from "./list";
3
3
  import { mkdir, rm, writeFile } from "node:fs/promises";
4
4
  import { join } from "node:path";
@@ -68,7 +68,7 @@ export const myFunc = {
68
68
 
69
69
  expect(result.success).toBe(true);
70
70
  const parsed = JSON.parse(result.output);
71
- expect(parsed).toBeArrayOfSize(1);
71
+ expect(parsed).toHaveLength(1);
72
72
  expect(parsed[0].name).toBe("myFunc");
73
73
  });
74
74