@intentius/chant 0.0.1

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 (271) hide show
  1. package/README.md +365 -0
  2. package/package.json +22 -0
  3. package/src/attrref.test.ts +148 -0
  4. package/src/attrref.ts +50 -0
  5. package/src/barrel.test.ts +157 -0
  6. package/src/barrel.ts +101 -0
  7. package/src/bench.test.ts +227 -0
  8. package/src/build.test.ts +437 -0
  9. package/src/build.ts +425 -0
  10. package/src/builder.test.ts +312 -0
  11. package/src/builder.ts +56 -0
  12. package/src/child-project.ts +44 -0
  13. package/src/cli/commands/__fixtures__/init-lexicon-output/README.md +26 -0
  14. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/astro.config.mjs +14 -0
  15. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/package.json +16 -0
  16. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content/docs/index.mdx +8 -0
  17. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content.config.ts +7 -0
  18. package/src/cli/commands/__fixtures__/init-lexicon-output/docs/tsconfig.json +10 -0
  19. package/src/cli/commands/__fixtures__/init-lexicon-output/examples/getting-started/.gitkeep +0 -0
  20. package/src/cli/commands/__fixtures__/init-lexicon-output/justfile +26 -0
  21. package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +29 -0
  22. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs.ts +25 -0
  23. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/generate-cli.ts +8 -0
  24. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/generate.ts +74 -0
  25. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/naming.ts +33 -0
  26. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +25 -0
  27. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/rollback.ts +45 -0
  28. package/src/cli/commands/__fixtures__/init-lexicon-output/src/coverage.ts +11 -0
  29. package/src/cli/commands/__fixtures__/init-lexicon-output/src/generated/.gitkeep +0 -0
  30. package/src/cli/commands/__fixtures__/init-lexicon-output/src/import/generator.ts +10 -0
  31. package/src/cli/commands/__fixtures__/init-lexicon-output/src/import/parser.ts +10 -0
  32. package/src/cli/commands/__fixtures__/init-lexicon-output/src/index.ts +9 -0
  33. package/src/cli/commands/__fixtures__/init-lexicon-output/src/lint/rules/index.ts +1 -0
  34. package/src/cli/commands/__fixtures__/init-lexicon-output/src/lint/rules/sample.ts +18 -0
  35. package/src/cli/commands/__fixtures__/init-lexicon-output/src/lsp/completions.ts +14 -0
  36. package/src/cli/commands/__fixtures__/init-lexicon-output/src/lsp/hover.ts +14 -0
  37. package/src/cli/commands/__fixtures__/init-lexicon-output/src/plugin.ts +110 -0
  38. package/src/cli/commands/__fixtures__/init-lexicon-output/src/serializer.ts +24 -0
  39. package/src/cli/commands/__fixtures__/init-lexicon-output/src/spec/fetch.ts +21 -0
  40. package/src/cli/commands/__fixtures__/init-lexicon-output/src/spec/parse.ts +25 -0
  41. package/src/cli/commands/__fixtures__/init-lexicon-output/src/validate-cli.ts +4 -0
  42. package/src/cli/commands/__fixtures__/init-lexicon-output/src/validate.ts +24 -0
  43. package/src/cli/commands/__fixtures__/init-lexicon-output/tsconfig.json +10 -0
  44. package/src/cli/commands/__fixtures__/sample-rule.ts +11 -0
  45. package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +222 -0
  46. package/src/cli/commands/build.test.ts +149 -0
  47. package/src/cli/commands/build.ts +344 -0
  48. package/src/cli/commands/diff.test.ts +148 -0
  49. package/src/cli/commands/diff.ts +221 -0
  50. package/src/cli/commands/doctor.test.ts +239 -0
  51. package/src/cli/commands/doctor.ts +224 -0
  52. package/src/cli/commands/import.test.ts +379 -0
  53. package/src/cli/commands/import.ts +335 -0
  54. package/src/cli/commands/init-lexicon.test.ts +297 -0
  55. package/src/cli/commands/init-lexicon.ts +993 -0
  56. package/src/cli/commands/init.test.ts +317 -0
  57. package/src/cli/commands/init.ts +505 -0
  58. package/src/cli/commands/licenses.ts +165 -0
  59. package/src/cli/commands/lint.test.ts +332 -0
  60. package/src/cli/commands/lint.ts +408 -0
  61. package/src/cli/commands/list.test.ts +100 -0
  62. package/src/cli/commands/list.ts +108 -0
  63. package/src/cli/commands/update.test.ts +38 -0
  64. package/src/cli/commands/update.ts +207 -0
  65. package/src/cli/conflict-check.test.ts +255 -0
  66. package/src/cli/conflict-check.ts +89 -0
  67. package/src/cli/debug.ts +8 -0
  68. package/src/cli/format.test.ts +140 -0
  69. package/src/cli/format.ts +133 -0
  70. package/src/cli/handlers/build.ts +58 -0
  71. package/src/cli/handlers/dev.ts +38 -0
  72. package/src/cli/handlers/init.ts +46 -0
  73. package/src/cli/handlers/lint.ts +36 -0
  74. package/src/cli/handlers/misc.ts +57 -0
  75. package/src/cli/handlers/serve.ts +26 -0
  76. package/src/cli/index.ts +3 -0
  77. package/src/cli/lsp/capabilities.ts +46 -0
  78. package/src/cli/lsp/diagnostics.ts +52 -0
  79. package/src/cli/lsp/server.test.ts +618 -0
  80. package/src/cli/lsp/server.ts +393 -0
  81. package/src/cli/main.test.ts +257 -0
  82. package/src/cli/main.ts +224 -0
  83. package/src/cli/mcp/resources/context.ts +59 -0
  84. package/src/cli/mcp/server.test.ts +747 -0
  85. package/src/cli/mcp/server.ts +402 -0
  86. package/src/cli/mcp/tools/build.ts +117 -0
  87. package/src/cli/mcp/tools/import.ts +48 -0
  88. package/src/cli/mcp/tools/lint.ts +45 -0
  89. package/src/cli/plugins.test.ts +31 -0
  90. package/src/cli/plugins.ts +94 -0
  91. package/src/cli/registry.ts +73 -0
  92. package/src/cli/reporters/stylish.test.ts +282 -0
  93. package/src/cli/reporters/stylish.ts +186 -0
  94. package/src/cli/watch.test.ts +81 -0
  95. package/src/cli/watch.ts +101 -0
  96. package/src/codegen/case.test.ts +30 -0
  97. package/src/codegen/case.ts +11 -0
  98. package/src/codegen/coverage.ts +167 -0
  99. package/src/codegen/docs.ts +634 -0
  100. package/src/codegen/fetch.test.ts +119 -0
  101. package/src/codegen/fetch.ts +261 -0
  102. package/src/codegen/generate-registry.test.ts +118 -0
  103. package/src/codegen/generate-registry.ts +107 -0
  104. package/src/codegen/generate-runtime-index.test.ts +81 -0
  105. package/src/codegen/generate-runtime-index.ts +99 -0
  106. package/src/codegen/generate-typescript.test.ts +146 -0
  107. package/src/codegen/generate-typescript.ts +161 -0
  108. package/src/codegen/generate.ts +206 -0
  109. package/src/codegen/json-patch.test.ts +113 -0
  110. package/src/codegen/json-patch.ts +151 -0
  111. package/src/codegen/json-schema.test.ts +196 -0
  112. package/src/codegen/json-schema.ts +209 -0
  113. package/src/codegen/naming.ts +201 -0
  114. package/src/codegen/package.ts +161 -0
  115. package/src/codegen/rollback.test.ts +92 -0
  116. package/src/codegen/rollback.ts +115 -0
  117. package/src/codegen/topo-sort.test.ts +69 -0
  118. package/src/codegen/topo-sort.ts +46 -0
  119. package/src/codegen/typecheck.test.ts +37 -0
  120. package/src/codegen/typecheck.ts +74 -0
  121. package/src/codegen/validate.test.ts +86 -0
  122. package/src/codegen/validate.ts +143 -0
  123. package/src/composite.test.ts +426 -0
  124. package/src/composite.ts +243 -0
  125. package/src/config.test.ts +91 -0
  126. package/src/config.ts +87 -0
  127. package/src/declarable.test.ts +160 -0
  128. package/src/declarable.ts +47 -0
  129. package/src/detectLexicon.test.ts +236 -0
  130. package/src/detectLexicon.ts +37 -0
  131. package/src/discovery/cache.test.ts +78 -0
  132. package/src/discovery/cache.ts +86 -0
  133. package/src/discovery/collect.test.ts +269 -0
  134. package/src/discovery/collect.ts +51 -0
  135. package/src/discovery/cycles.test.ts +238 -0
  136. package/src/discovery/cycles.ts +107 -0
  137. package/src/discovery/files.test.ts +154 -0
  138. package/src/discovery/files.ts +61 -0
  139. package/src/discovery/graph.test.ts +476 -0
  140. package/src/discovery/graph.ts +150 -0
  141. package/src/discovery/import.test.ts +199 -0
  142. package/src/discovery/import.ts +20 -0
  143. package/src/discovery/index.test.ts +272 -0
  144. package/src/discovery/index.ts +132 -0
  145. package/src/discovery/resolve.test.ts +267 -0
  146. package/src/discovery/resolve.ts +54 -0
  147. package/src/errors.test.ts +138 -0
  148. package/src/errors.ts +86 -0
  149. package/src/import/base-parser.test.ts +67 -0
  150. package/src/import/base-parser.ts +48 -0
  151. package/src/import/generator.ts +21 -0
  152. package/src/import/ir-utils.test.ts +103 -0
  153. package/src/import/ir-utils.ts +87 -0
  154. package/src/import/parser.ts +41 -0
  155. package/src/index.ts +60 -0
  156. package/src/intrinsic-interpolation.test.ts +91 -0
  157. package/src/intrinsic-interpolation.ts +89 -0
  158. package/src/intrinsic.test.ts +69 -0
  159. package/src/intrinsic.ts +43 -0
  160. package/src/lexicon-integrity.test.ts +94 -0
  161. package/src/lexicon-integrity.ts +69 -0
  162. package/src/lexicon-manifest.test.ts +101 -0
  163. package/src/lexicon-manifest.ts +71 -0
  164. package/src/lexicon-output.test.ts +182 -0
  165. package/src/lexicon-output.ts +82 -0
  166. package/src/lexicon-schema.test.ts +239 -0
  167. package/src/lexicon-schema.ts +144 -0
  168. package/src/lexicon.ts +212 -0
  169. package/src/lint/config-overrides.test.ts +254 -0
  170. package/src/lint/config.test.ts +644 -0
  171. package/src/lint/config.ts +375 -0
  172. package/src/lint/declarative.test.ts +256 -0
  173. package/src/lint/declarative.ts +187 -0
  174. package/src/lint/engine.test.ts +465 -0
  175. package/src/lint/engine.ts +172 -0
  176. package/src/lint/named-checks.test.ts +37 -0
  177. package/src/lint/named-checks.ts +33 -0
  178. package/src/lint/parser.test.ts +129 -0
  179. package/src/lint/parser.ts +42 -0
  180. package/src/lint/post-synth.test.ts +113 -0
  181. package/src/lint/post-synth.ts +76 -0
  182. package/src/lint/presets/relaxed.json +19 -0
  183. package/src/lint/presets/strict.json +19 -0
  184. package/src/lint/rule-loader.test.ts +67 -0
  185. package/src/lint/rule-loader.ts +67 -0
  186. package/src/lint/rule-options.test.ts +141 -0
  187. package/src/lint/rule.test.ts +196 -0
  188. package/src/lint/rule.ts +98 -0
  189. package/src/lint/rules/barrel-import-style.test.ts +80 -0
  190. package/src/lint/rules/barrel-import-style.ts +59 -0
  191. package/src/lint/rules/composite-scope.ts +55 -0
  192. package/src/lint/rules/cor017-composite-name-match.test.ts +107 -0
  193. package/src/lint/rules/cor017-composite-name-match.ts +108 -0
  194. package/src/lint/rules/cor018-composite-prefer-lexicon-type.test.ts +172 -0
  195. package/src/lint/rules/cor018-composite-prefer-lexicon-type.ts +167 -0
  196. package/src/lint/rules/declarable-naming-convention.test.ts +69 -0
  197. package/src/lint/rules/declarable-naming-convention.ts +70 -0
  198. package/src/lint/rules/enforce-barrel-import.test.ts +169 -0
  199. package/src/lint/rules/enforce-barrel-import.ts +81 -0
  200. package/src/lint/rules/enforce-barrel-ref.test.ts +114 -0
  201. package/src/lint/rules/enforce-barrel-ref.ts +75 -0
  202. package/src/lint/rules/evl001-non-literal-expression.test.ts +158 -0
  203. package/src/lint/rules/evl001-non-literal-expression.ts +149 -0
  204. package/src/lint/rules/evl002-control-flow-resource.test.ts +110 -0
  205. package/src/lint/rules/evl002-control-flow-resource.ts +61 -0
  206. package/src/lint/rules/evl003-dynamic-property-access.test.ts +63 -0
  207. package/src/lint/rules/evl003-dynamic-property-access.ts +41 -0
  208. package/src/lint/rules/evl004-spread-non-const.test.ts +130 -0
  209. package/src/lint/rules/evl004-spread-non-const.ts +111 -0
  210. package/src/lint/rules/evl005-resource-block-body.test.ts +59 -0
  211. package/src/lint/rules/evl005-resource-block-body.ts +49 -0
  212. package/src/lint/rules/evl006-barrel-usage.test.ts +63 -0
  213. package/src/lint/rules/evl006-barrel-usage.ts +95 -0
  214. package/src/lint/rules/evl007-invalid-siblings.test.ts +87 -0
  215. package/src/lint/rules/evl007-invalid-siblings.ts +139 -0
  216. package/src/lint/rules/evl008-unresolvable-barrel-ref.test.ts +118 -0
  217. package/src/lint/rules/evl008-unresolvable-barrel-ref.ts +140 -0
  218. package/src/lint/rules/evl009-composite-no-constant.test.ts +162 -0
  219. package/src/lint/rules/evl009-composite-no-constant.ts +171 -0
  220. package/src/lint/rules/evl010-composite-no-transform.test.ts +121 -0
  221. package/src/lint/rules/evl010-composite-no-transform.ts +69 -0
  222. package/src/lint/rules/export-required.test.ts +213 -0
  223. package/src/lint/rules/export-required.ts +158 -0
  224. package/src/lint/rules/file-declarable-limit.test.ts +148 -0
  225. package/src/lint/rules/file-declarable-limit.ts +96 -0
  226. package/src/lint/rules/flat-declarations.test.ts +210 -0
  227. package/src/lint/rules/flat-declarations.ts +70 -0
  228. package/src/lint/rules/index.ts +99 -0
  229. package/src/lint/rules/no-cyclic-declarable-ref.test.ts +135 -0
  230. package/src/lint/rules/no-cyclic-declarable-ref.ts +178 -0
  231. package/src/lint/rules/no-redundant-type-import.test.ts +129 -0
  232. package/src/lint/rules/no-redundant-type-import.ts +85 -0
  233. package/src/lint/rules/no-redundant-value-cast.test.ts +51 -0
  234. package/src/lint/rules/no-redundant-value-cast.ts +46 -0
  235. package/src/lint/rules/no-string-ref.test.ts +100 -0
  236. package/src/lint/rules/no-string-ref.ts +66 -0
  237. package/src/lint/rules/no-unused-declarable-import.test.ts +74 -0
  238. package/src/lint/rules/no-unused-declarable-import.ts +103 -0
  239. package/src/lint/rules/no-unused-declarable.test.ts +134 -0
  240. package/src/lint/rules/no-unused-declarable.ts +118 -0
  241. package/src/lint/rules/prefer-namespace-import.test.ts +102 -0
  242. package/src/lint/rules/prefer-namespace-import.ts +63 -0
  243. package/src/lint/rules/single-concern-file.test.ts +156 -0
  244. package/src/lint/rules/single-concern-file.ts +98 -0
  245. package/src/lint/rules/stale-barrel-types.ts +60 -0
  246. package/src/lint/selectors.test.ts +113 -0
  247. package/src/lint/selectors.ts +188 -0
  248. package/src/lsp/lexicon-providers.ts +191 -0
  249. package/src/lsp/types.ts +79 -0
  250. package/src/mcp/types.ts +22 -0
  251. package/src/project/scan.test.ts +178 -0
  252. package/src/project/scan.ts +182 -0
  253. package/src/project/sync.test.ts +87 -0
  254. package/src/project/sync.ts +46 -0
  255. package/src/project-validation.test.ts +64 -0
  256. package/src/project-validation.ts +79 -0
  257. package/src/pseudo-parameter.test.ts +39 -0
  258. package/src/pseudo-parameter.ts +47 -0
  259. package/src/runtime.ts +68 -0
  260. package/src/serializer-walker.test.ts +124 -0
  261. package/src/serializer-walker.ts +83 -0
  262. package/src/serializer.ts +42 -0
  263. package/src/sort.test.ts +290 -0
  264. package/src/sort.ts +58 -0
  265. package/src/stack-output.ts +82 -0
  266. package/src/types.test.ts +307 -0
  267. package/src/types.ts +46 -0
  268. package/src/utils.test.ts +195 -0
  269. package/src/utils.ts +46 -0
  270. package/src/validation.test.ts +308 -0
  271. package/src/validation.ts +50 -0
@@ -0,0 +1,133 @@
1
+ /**
2
+ * ANSI color codes for terminal output
3
+ */
4
+ const colors = {
5
+ red: "\x1b[31m",
6
+ yellow: "\x1b[33m",
7
+ green: "\x1b[32m",
8
+ cyan: "\x1b[36m",
9
+ gray: "\x1b[90m",
10
+ reset: "\x1b[0m",
11
+ bold: "\x1b[1m",
12
+ };
13
+
14
+ /**
15
+ * Check if colors should be used (respects NO_COLOR env var)
16
+ */
17
+ function useColors(): boolean {
18
+ return !process.env.NO_COLOR && process.stdout.isTTY !== false;
19
+ }
20
+
21
+ /**
22
+ * Apply color if colors are enabled
23
+ */
24
+ function color(text: string, colorCode: string): string {
25
+ if (!useColors()) return text;
26
+ return `${colorCode}${text}${colors.reset}`;
27
+ }
28
+
29
+ /**
30
+ * Format an error with ANSI colors
31
+ * Shows file:line:column in cyan, error in red
32
+ */
33
+ export function formatError(error: {
34
+ file?: string;
35
+ line?: number;
36
+ column?: number;
37
+ message: string;
38
+ name?: string;
39
+ hint?: string;
40
+ }): string {
41
+ const parts: string[] = [];
42
+
43
+ // Location prefix
44
+ if (error.file) {
45
+ let location = error.file;
46
+ if (error.line !== undefined) {
47
+ location += `:${error.line}`;
48
+ if (error.column !== undefined) {
49
+ location += `:${error.column}`;
50
+ }
51
+ }
52
+ parts.push(color(location, colors.cyan));
53
+ parts.push(" - ");
54
+ }
55
+
56
+ // Error type
57
+ parts.push(color("error", colors.red));
58
+ parts.push(": ");
59
+
60
+ // Message
61
+ parts.push(error.message);
62
+
63
+ // Hint
64
+ if (error.hint) {
65
+ parts.push("\n ");
66
+ parts.push(color(error.hint, colors.gray));
67
+ }
68
+
69
+ return parts.join("");
70
+ }
71
+
72
+ /**
73
+ * Format a warning with ANSI colors
74
+ * Shows file:line:column in cyan, warning in yellow
75
+ */
76
+ export function formatWarning(warning: {
77
+ file?: string;
78
+ line?: number;
79
+ column?: number;
80
+ message: string;
81
+ hint?: string;
82
+ }): string {
83
+ const parts: string[] = [];
84
+
85
+ // Location prefix
86
+ if (warning.file) {
87
+ let location = warning.file;
88
+ if (warning.line !== undefined) {
89
+ location += `:${warning.line}`;
90
+ if (warning.column !== undefined) {
91
+ location += `:${warning.column}`;
92
+ }
93
+ }
94
+ parts.push(color(location, colors.cyan));
95
+ parts.push(" - ");
96
+ }
97
+
98
+ // Warning type
99
+ parts.push(color("warning", colors.yellow));
100
+ parts.push(": ");
101
+
102
+ // Message
103
+ parts.push(warning.message);
104
+
105
+ // Hint
106
+ if (warning.hint) {
107
+ parts.push("\n ");
108
+ parts.push(color(warning.hint, colors.gray));
109
+ }
110
+
111
+ return parts.join("");
112
+ }
113
+
114
+ /**
115
+ * Format a success message in green
116
+ */
117
+ export function formatSuccess(message: string): string {
118
+ return color(message, colors.green);
119
+ }
120
+
121
+ /**
122
+ * Format an info message in gray
123
+ */
124
+ export function formatInfo(message: string): string {
125
+ return color(message, colors.gray);
126
+ }
127
+
128
+ /**
129
+ * Format a count/stat in bold
130
+ */
131
+ export function formatBold(text: string): string {
132
+ return color(text, colors.bold);
133
+ }
@@ -0,0 +1,58 @@
1
+ import { buildCommand, buildCommandWatch, printErrors, printWarnings } from "../commands/build";
2
+ import { formatInfo } from "../format";
3
+ import type { CommandContext } from "../registry";
4
+
5
+ export async function runBuild(ctx: CommandContext): Promise<number> {
6
+ const { args, plugins } = ctx;
7
+ let { serializers } = ctx;
8
+
9
+ // Filter to a single lexicon when --lexicon is specified
10
+ if (args.lexicon) {
11
+ serializers = serializers.filter((s) => s.name === args.lexicon);
12
+ if (serializers.length === 0) {
13
+ console.error(`No serializer found for lexicon "${args.lexicon}". Available: ${ctx.serializers.map((s) => s.name).join(", ")}`);
14
+ return 1;
15
+ }
16
+ }
17
+
18
+ const buildFormat = (args.format || "json") as "json" | "yaml";
19
+ if (buildFormat !== "json" && buildFormat !== "yaml") {
20
+ console.error(`Invalid format for build: ${buildFormat}. Expected 'json' or 'yaml'.`);
21
+ return 1;
22
+ }
23
+
24
+ if (args.watch) {
25
+ const cleanup = buildCommandWatch({
26
+ path: args.path,
27
+ output: args.output,
28
+ format: buildFormat,
29
+ serializers,
30
+ plugins,
31
+ });
32
+ process.on("SIGINT", () => {
33
+ cleanup();
34
+ console.error(formatInfo("\nWatch mode stopped."));
35
+ process.exit(0);
36
+ });
37
+ await new Promise(() => {});
38
+ }
39
+
40
+ const result = await buildCommand({
41
+ path: args.path,
42
+ output: args.output,
43
+ format: buildFormat,
44
+ serializers,
45
+ plugins,
46
+ verbose: args.verbose,
47
+ });
48
+
49
+ // When --lexicon filters to a subset, suppress "No serializer" warnings for excluded lexicons
50
+ let warnings = result.warnings;
51
+ if (args.lexicon) {
52
+ warnings = warnings.filter((w) => !w.includes('No serializer found for lexicon'));
53
+ }
54
+ printWarnings(warnings);
55
+ printErrors(result.errors);
56
+
57
+ return result.success ? 0 : 1;
58
+ }
@@ -0,0 +1,38 @@
1
+ import { formatError, formatSuccess } from "../format";
2
+ import type { CommandContext } from "../registry";
3
+
4
+ export async function runDevGenerate(ctx: CommandContext): Promise<number> {
5
+ for (const plugin of ctx.plugins) {
6
+ await plugin.generate({ verbose: ctx.args.verbose });
7
+ console.error(formatSuccess(`${plugin.name}: generate complete`));
8
+ await plugin.validate({ verbose: ctx.args.verbose });
9
+ console.error(formatSuccess(`${plugin.name}: validate complete`));
10
+ await plugin.coverage({ verbose: ctx.args.verbose });
11
+ console.error(formatSuccess(`${plugin.name}: coverage complete`));
12
+ }
13
+ return 0;
14
+ }
15
+
16
+ export async function runDevPublish(ctx: CommandContext): Promise<number> {
17
+ for (const plugin of ctx.plugins) {
18
+ await plugin.package({ verbose: ctx.args.verbose, force: ctx.args.force });
19
+ console.error(formatSuccess(`${plugin.name}: publish complete`));
20
+ }
21
+ return 0;
22
+ }
23
+
24
+ export async function runDevRollback(ctx: CommandContext): Promise<number> {
25
+ for (const plugin of ctx.plugins) {
26
+ await plugin.rollback({ verbose: ctx.args.verbose });
27
+ console.error(formatSuccess(`${plugin.name}: rollback complete`));
28
+ }
29
+ return 0;
30
+ }
31
+
32
+ export async function runDevUnknown(ctx: CommandContext): Promise<number> {
33
+ console.error(formatError({
34
+ message: `Unknown dev subcommand: ${ctx.args.path}`,
35
+ hint: "Available: chant dev generate, chant dev publish, chant dev rollback",
36
+ }));
37
+ return 1;
38
+ }
@@ -0,0 +1,46 @@
1
+ import { formatError } from "../format";
2
+ import type { CommandContext } from "../registry";
3
+
4
+ export async function runInit(ctx: CommandContext): Promise<number> {
5
+ const { args } = ctx;
6
+
7
+ if (!args.lexicon) {
8
+ console.error(formatError({
9
+ message: "Missing --lexicon flag",
10
+ hint: "Usage: chant init --lexicon <name>",
11
+ }));
12
+ return 1;
13
+ }
14
+
15
+ const { initCommand, printInitResult } = await import("../commands/init");
16
+ const result = await initCommand({
17
+ path: args.path === "." ? undefined : args.path,
18
+ lexicon: args.lexicon,
19
+ force: args.force,
20
+ skipInstall: true,
21
+ });
22
+ await printInitResult(result, { skipInstall: false, cwd: args.path });
23
+ return result.success ? 0 : 1;
24
+ }
25
+
26
+ export async function runInitLexicon(ctx: CommandContext): Promise<number> {
27
+ const { args } = ctx;
28
+
29
+ const name = args.extraPositional;
30
+ if (!name) {
31
+ console.error(formatError({
32
+ message: "Missing lexicon name",
33
+ hint: "Usage: chant init lexicon <name> [path]",
34
+ }));
35
+ return 1;
36
+ }
37
+
38
+ const { initLexiconCommand, printInitLexiconResult } = await import("../commands/init-lexicon");
39
+ const result = await initLexiconCommand({
40
+ name,
41
+ path: args.extraPositional2,
42
+ force: args.force,
43
+ });
44
+ await printInitLexiconResult(result);
45
+ return result.success ? 0 : 1;
46
+ }
@@ -0,0 +1,36 @@
1
+ import { lintCommand, lintCommandWatch, printLintResult } from "../commands/lint";
2
+ import { formatInfo } from "../format";
3
+ import type { CommandContext } from "../registry";
4
+
5
+ export async function runLint(ctx: CommandContext): Promise<number> {
6
+ const { args } = ctx;
7
+
8
+ const lintFormat = (args.format || "stylish") as "stylish" | "json" | "sarif";
9
+ if (lintFormat !== "stylish" && lintFormat !== "json" && lintFormat !== "sarif") {
10
+ console.error(`Invalid format for lint: ${lintFormat}. Expected 'stylish', 'json', or 'sarif'.`);
11
+ return 1;
12
+ }
13
+
14
+ if (args.watch) {
15
+ const cleanup = lintCommandWatch({
16
+ path: args.path,
17
+ fix: args.fix,
18
+ format: lintFormat,
19
+ });
20
+ process.on("SIGINT", () => {
21
+ cleanup();
22
+ console.error(formatInfo("\nWatch mode stopped."));
23
+ process.exit(0);
24
+ });
25
+ await new Promise(() => {});
26
+ }
27
+
28
+ const result = await lintCommand({
29
+ path: args.path,
30
+ fix: args.fix,
31
+ format: lintFormat,
32
+ });
33
+
34
+ printLintResult(result);
35
+ return result.success ? 0 : 1;
36
+ }
@@ -0,0 +1,57 @@
1
+ import { listCommand, printListResult } from "../commands/list";
2
+ import { importCommand, printImportResult } from "../commands/import";
3
+ import { formatError, formatSuccess } from "../format";
4
+ import type { CommandContext } from "../registry";
5
+
6
+ export async function runList(ctx: CommandContext): Promise<number> {
7
+ const { args } = ctx;
8
+ const listFormat = (args.format || "text") as "text" | "json";
9
+ if (listFormat !== "text" && listFormat !== "json") {
10
+ console.error(`Invalid format for list: ${listFormat}. Expected 'text' or 'json'.`);
11
+ return 1;
12
+ }
13
+
14
+ const result = await listCommand({
15
+ path: args.path,
16
+ format: listFormat,
17
+ });
18
+
19
+ printListResult(result);
20
+ return result.success ? 0 : 1;
21
+ }
22
+
23
+ export async function runImport(ctx: CommandContext): Promise<number> {
24
+ const result = await importCommand({
25
+ templatePath: ctx.args.path,
26
+ output: ctx.args.output,
27
+ force: ctx.args.force,
28
+ });
29
+
30
+ printImportResult(result);
31
+ return result.success ? 0 : 1;
32
+ }
33
+
34
+ export async function runUpdate(ctx: CommandContext): Promise<number> {
35
+ const { updateCommand, printUpdateResult } = await import("../commands/update");
36
+ const result = await updateCommand({ path: ctx.args.path });
37
+ printUpdateResult(result);
38
+ return result.success ? 0 : 1;
39
+ }
40
+
41
+ export async function runDoctor(ctx: CommandContext): Promise<number> {
42
+ const { doctorCommand } = await import("../commands/doctor");
43
+ const report = await doctorCommand(ctx.args.path);
44
+
45
+ for (const check of report.checks) {
46
+ const icon = check.status === "pass" ? "OK" : check.status === "warn" ? "WARN" : "FAIL";
47
+ const msg = check.message ? ` — ${check.message}` : "";
48
+ console.error(` [${icon}] ${check.name}${msg}`);
49
+ }
50
+
51
+ if (!report.success) {
52
+ console.error(formatError({ message: "Doctor found issues" }));
53
+ } else {
54
+ console.error(formatSuccess("All checks passed"));
55
+ }
56
+ return report.success ? 0 : 1;
57
+ }
@@ -0,0 +1,26 @@
1
+ import { formatError } from "../format";
2
+ import type { CommandContext } from "../registry";
3
+
4
+ export async function runServeLsp(ctx: CommandContext): Promise<number> {
5
+ const { LspServer } = await import("../lsp/server");
6
+ const server = new LspServer(ctx.plugins);
7
+ await server.start();
8
+ await new Promise(() => {});
9
+ return 0; // unreachable
10
+ }
11
+
12
+ export async function runServeMcp(ctx: CommandContext): Promise<number> {
13
+ const { McpServer } = await import("../mcp/server");
14
+ const server = new McpServer(ctx.plugins);
15
+ await server.start();
16
+ await new Promise(() => {});
17
+ return 0; // unreachable
18
+ }
19
+
20
+ export async function runServeUnknown(ctx: CommandContext): Promise<number> {
21
+ console.error(formatError({
22
+ message: `Unknown serve subcommand: ${ctx.args.path}`,
23
+ hint: "Available: chant serve lsp, chant serve mcp",
24
+ }));
25
+ return 1;
26
+ }
@@ -0,0 +1,3 @@
1
+ export { parseArgs } from "./main";
2
+ export { loadPlugin, loadPlugins, resolveProjectLexicons } from "./plugins";
3
+ export { checkConflicts } from "./conflict-check";
@@ -0,0 +1,46 @@
1
+ import type { LexiconPlugin } from "../../lexicon";
2
+
3
+ /**
4
+ * LSP server capabilities, conditionally advertised based on loaded plugins.
5
+ */
6
+ export interface LspCapabilities {
7
+ textDocumentSync: number;
8
+ completionProvider?: { triggerCharacters: string[] };
9
+ hoverProvider?: boolean;
10
+ codeActionProvider?: boolean;
11
+ diagnosticProvider?: { interFileDependencies: boolean; workspaceDiagnostics: boolean };
12
+ }
13
+
14
+ /**
15
+ * Compute LSP capabilities based on which plugins implement providers.
16
+ */
17
+ export function computeCapabilities(plugins: LexiconPlugin[]): LspCapabilities {
18
+ const hasCompletion = plugins.some((p) => p.completionProvider !== undefined);
19
+ const hasHover = plugins.some((p) => p.hoverProvider !== undefined);
20
+ const hasCodeAction = plugins.some((p) => p.codeActionProvider !== undefined);
21
+
22
+ const capabilities: LspCapabilities = {
23
+ // Full sync — client sends full document content on open/change
24
+ textDocumentSync: 1,
25
+ diagnosticProvider: {
26
+ interFileDependencies: false,
27
+ workspaceDiagnostics: false,
28
+ },
29
+ };
30
+
31
+ if (hasCompletion) {
32
+ capabilities.completionProvider = {
33
+ triggerCharacters: [".", " ", '"', "'", "`", "("],
34
+ };
35
+ }
36
+
37
+ if (hasHover) {
38
+ capabilities.hoverProvider = true;
39
+ }
40
+
41
+ if (hasCodeAction) {
42
+ capabilities.codeActionProvider = true;
43
+ }
44
+
45
+ return capabilities;
46
+ }
@@ -0,0 +1,52 @@
1
+ import type { LintDiagnostic, Severity } from "../../lint/rule";
2
+
3
+ /**
4
+ * LSP diagnostic as returned in textDocument/publishDiagnostics.
5
+ */
6
+ export interface LspDiagnostic {
7
+ range: {
8
+ start: { line: number; character: number };
9
+ end: { line: number; character: number };
10
+ };
11
+ severity: number;
12
+ code?: string;
13
+ source: string;
14
+ message: string;
15
+ data?: { ruleId: string; fix?: unknown };
16
+ }
17
+
18
+ /**
19
+ * Map chant severity to LSP DiagnosticSeverity (1=Error, 2=Warning, 3=Info, 4=Hint)
20
+ */
21
+ function toLspSeverity(severity: Severity): number {
22
+ switch (severity) {
23
+ case "error":
24
+ return 1;
25
+ case "warning":
26
+ return 2;
27
+ case "info":
28
+ return 3;
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Convert chant LintDiagnostics to LSP diagnostics.
34
+ * Converts 1-based lines/columns to 0-based.
35
+ */
36
+ export function toLspDiagnostics(diagnostics: LintDiagnostic[]): LspDiagnostic[] {
37
+ return diagnostics.map((d) => {
38
+ const line = Math.max(0, d.line - 1);
39
+ const character = Math.max(0, d.column - 1);
40
+ return {
41
+ range: {
42
+ start: { line, character },
43
+ end: { line, character },
44
+ },
45
+ severity: toLspSeverity(d.severity),
46
+ code: d.ruleId,
47
+ source: "chant",
48
+ message: d.message,
49
+ data: d.fix ? { ruleId: d.ruleId, fix: d.fix } : { ruleId: d.ruleId },
50
+ };
51
+ });
52
+ }