@intentius/chant 0.0.4 → 0.0.8

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 (75) hide show
  1. package/README.md +10 -351
  2. package/bin/chant +20 -0
  3. package/package.json +18 -17
  4. package/src/bench.test.ts +3 -54
  5. package/src/cli/commands/__fixtures__/init-lexicon-output/src/plugin.ts +8 -23
  6. package/src/cli/commands/__fixtures__/init-lexicon-output/src/validate.ts +22 -18
  7. package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +8 -23
  8. package/src/cli/commands/build.ts +1 -2
  9. package/src/cli/commands/import.test.ts +1 -1
  10. package/src/cli/commands/import.ts +2 -2
  11. package/src/cli/commands/init-lexicon.test.ts +0 -3
  12. package/src/cli/commands/init-lexicon.ts +31 -95
  13. package/src/cli/commands/init.test.ts +10 -14
  14. package/src/cli/commands/init.ts +16 -10
  15. package/src/cli/commands/lint.ts +9 -33
  16. package/src/cli/commands/list.ts +2 -2
  17. package/src/cli/commands/update.ts +5 -3
  18. package/src/cli/conflict-check.test.ts +0 -1
  19. package/src/cli/handlers/dev.ts +1 -9
  20. package/src/cli/main.ts +14 -4
  21. package/src/cli/mcp/server.test.ts +207 -4
  22. package/src/cli/mcp/server.ts +6 -0
  23. package/src/cli/mcp/tools/explain.ts +134 -0
  24. package/src/cli/mcp/tools/scaffold.ts +107 -0
  25. package/src/cli/mcp/tools/search.ts +98 -0
  26. package/src/codegen/docs-interpolation.test.ts +2 -2
  27. package/src/codegen/docs.ts +5 -4
  28. package/src/codegen/generate-registry.test.ts +2 -2
  29. package/src/codegen/generate-registry.ts +5 -6
  30. package/src/codegen/generate-typescript.test.ts +6 -6
  31. package/src/codegen/generate-typescript.ts +2 -6
  32. package/src/codegen/generate.ts +1 -12
  33. package/src/codegen/package.ts +28 -1
  34. package/src/codegen/typecheck.ts +6 -11
  35. package/src/codegen/validate.ts +16 -0
  36. package/src/config.ts +4 -0
  37. package/src/discovery/files.ts +6 -6
  38. package/src/discovery/import.ts +1 -1
  39. package/src/index.ts +1 -2
  40. package/src/lexicon-integrity.ts +5 -4
  41. package/src/lexicon.ts +2 -6
  42. package/src/lint/config.ts +8 -6
  43. package/src/lint/engine.ts +1 -5
  44. package/src/lint/rule.ts +0 -18
  45. package/src/lint/rules/evl009-composite-no-constant.test.ts +24 -8
  46. package/src/lint/rules/evl009-composite-no-constant.ts +50 -29
  47. package/src/lint/rules/index.ts +1 -22
  48. package/src/runtime-adapter.ts +158 -0
  49. package/src/serializer-walker.test.ts +0 -9
  50. package/src/serializer-walker.ts +1 -3
  51. package/src/stack-output.ts +3 -3
  52. package/src/barrel.test.ts +0 -157
  53. package/src/barrel.ts +0 -101
  54. package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/rollback.ts +0 -45
  55. package/src/codegen/case.test.ts +0 -30
  56. package/src/codegen/case.ts +0 -11
  57. package/src/codegen/rollback.test.ts +0 -92
  58. package/src/codegen/rollback.ts +0 -115
  59. package/src/lint/rules/barrel-import-style.test.ts +0 -80
  60. package/src/lint/rules/barrel-import-style.ts +0 -59
  61. package/src/lint/rules/enforce-barrel-import.test.ts +0 -169
  62. package/src/lint/rules/enforce-barrel-import.ts +0 -81
  63. package/src/lint/rules/enforce-barrel-ref.test.ts +0 -114
  64. package/src/lint/rules/enforce-barrel-ref.ts +0 -75
  65. package/src/lint/rules/evl006-barrel-usage.test.ts +0 -63
  66. package/src/lint/rules/evl006-barrel-usage.ts +0 -95
  67. package/src/lint/rules/evl008-unresolvable-barrel-ref.test.ts +0 -118
  68. package/src/lint/rules/evl008-unresolvable-barrel-ref.ts +0 -140
  69. package/src/lint/rules/prefer-namespace-import.test.ts +0 -102
  70. package/src/lint/rules/prefer-namespace-import.ts +0 -63
  71. package/src/lint/rules/stale-barrel-types.ts +0 -60
  72. package/src/project/scan.test.ts +0 -178
  73. package/src/project/scan.ts +0 -182
  74. package/src/project/sync.test.ts +0 -87
  75. package/src/project/sync.ts +0 -46
package/README.md CHANGED
@@ -1,364 +1,23 @@
1
1
  # @intentius/chant
2
2
 
3
- > Part of the [chant](../../README.md) monorepo. Published as [`@intentius/chant`](https://www.npmjs.com/package/@intentius/chant) on npm.
3
+ Core package for [chant](https://intentius.io/chant/) a type system for operations.
4
4
 
5
- Core functionality for chant - a lexicon-agnostic declarative infrastructure specification system.
5
+ This package provides the lexicon-agnostic foundation that all chant lexicons build on. It includes the type system (Declarables, Intrinsics, Parameters, Outputs), the discovery and build pipeline, the semantic lint engine, the CLI, template import, and reusable codegen infrastructure for lexicon authors (runtime factories, naming strategies, generation and packaging pipelines, LSP providers).
6
6
 
7
- ## Overview
7
+ Install it alongside a lexicon to start declaring infrastructure as typed TypeScript.
8
8
 
9
- This package provides the foundational types, interfaces, and utilities that power chant's declarative infrastructure system. It includes:
10
-
11
- - **Type system**: Declarables, Intrinsics, Parameters, and Outputs
12
- - **Discovery system**: File scanning, module loading, and entity collection
13
- - **Build pipeline**: Dependency resolution, topological sorting, and serialization
14
- - **Error handling**: Structured errors for discovery, build, and lint phases
15
- - **Lint system**: Infrastructure code validation framework
16
- - **Template import**: Convert external templates to TypeScript
17
- - **Codegen infrastructure**: Reusable pipelines for generating, naming, packaging, and fetching schemas
18
- - **LSP providers**: Generic lexicon-based completion and hover helpers
19
- - **Runtime factories**: `createResource` and `createProperty` for Declarable-marked constructors
20
-
21
- ## Key Concepts
22
-
23
- ### Declarables
24
-
25
- A `Declarable` is any entity that can be declared in an infrastructure specification:
26
-
27
- ```typescript
28
- import { isDeclarable, DECLARABLE_MARKER } from "@intentius/chant";
29
-
30
- if (isDeclarable(value)) {
31
- console.log(value.entityType);
32
- }
33
- ```
34
-
35
- ### Intrinsics
36
-
37
- An `Intrinsic` represents a lexicon-provided function resolved at build time:
38
-
39
- ```typescript
40
- import { isIntrinsic, INTRINSIC_MARKER } from "@intentius/chant";
41
-
42
- if (isIntrinsic(value)) {
43
- const serialized = value.toJSON();
44
- }
45
- ```
46
-
47
- ### AttrRef
48
-
49
- Reference attributes of other entities with deferred resolution:
50
-
51
- ```typescript
52
- import { AttrRef } from "@intentius/chant";
53
-
54
- const bucket = {};
55
- const arnRef = new AttrRef(bucket, "arn");
56
-
57
- // Later, during discovery
58
- arnRef._setLogicalName("MyBucket");
59
- arnRef.toJSON(); // { "Fn::GetAttr": ["MyBucket", "arn"] }
60
- ```
61
-
62
- ## Discovery System
63
-
64
- Discover and collect infrastructure entities from TypeScript files:
65
-
66
- ```typescript
67
- import { discover } from "@intentius/chant";
68
-
69
- const result = await discover("./src/infra");
70
- // result.entities: Map of entity name to Declarable
71
- // result.dependencies: Dependency graph
72
- // result.sourceFiles: Discovered files
73
- // result.errors: Any errors encountered
74
- ```
75
-
76
- ### Individual Discovery Functions
77
-
78
- ```typescript
79
- import {
80
- findInfraFiles,
81
- importModule,
82
- collectEntities,
83
- resolveAttrRefs,
84
- buildDependencyGraph,
85
- detectCycles,
86
- topologicalSort,
87
- } from "@intentius/chant";
88
-
89
- // Find all .ts files (excluding tests and node_modules)
90
- const files = await findInfraFiles("./src");
91
-
92
- // Import a module
93
- const exports = await importModule("./src/resources.ts");
94
-
95
- // Collect declarables from modules
96
- const entities = collectEntities([
97
- { file: "resources.ts", exports }
98
- ]);
99
-
100
- // Resolve attribute references
101
- resolveAttrRefs(entities);
102
-
103
- // Build dependency graph
104
- const deps = buildDependencyGraph(entities);
105
-
106
- // Check for cycles
107
- const cycles = detectCycles(deps);
108
-
109
- // Topological sort
110
- const order = topologicalSort(deps);
111
- ```
112
-
113
- ## Build Pipeline
114
-
115
- Build infrastructure specifications with lexicon-specific serialization:
116
-
117
- ```typescript
118
- import { build } from "@intentius/chant";
119
- import { myLexicon } from "@intentius/chant-lexicon-myplatform";
120
-
121
- const result = await build("./src/infra", [myLexicon]);
122
- // result.outputs: Map of lexicon name to serialized output
123
- // result.entities: Discovered entities
124
- // result.warnings: Build warnings
125
- // result.errors: Any errors
126
- ```
127
-
128
- ## Error Handling
129
-
130
- Structured error types for different phases:
131
-
132
- ```typescript
133
- import { DiscoveryError, BuildError, LintError } from "@intentius/chant";
134
-
135
- // Discovery phase errors
136
- throw new DiscoveryError("config.ts", "Module not found", "import");
137
-
138
- // Build phase errors
139
- throw new BuildError("MyResource", "Invalid configuration");
140
-
141
- // Lint errors with location
142
- const error = new LintError(
143
- "config.ts",
144
- 10,
145
- 5,
146
- "no-unused",
147
- "Variable is declared but never used"
148
- );
149
-
150
- // All errors support JSON serialization
151
- const json = error.toJSON();
152
- ```
153
-
154
- ## Lint System
155
-
156
- Validate infrastructure code with custom rules:
157
-
158
- ```typescript
159
- import { parseFile } from "@intentius/chant";
160
- import type { LintRule, LintContext } from "@intentius/chant";
161
-
162
- // Parse a file for linting
163
- const sourceFile = parseFile("./src/infra/main.ts");
164
-
165
- // Define a lint rule
166
- const myRule: LintRule = {
167
- id: "my-rule",
168
- severity: "error",
169
- category: "correctness",
170
- check(context: LintContext): LintDiagnostic[] {
171
- // Analyze context.sourceFile
172
- return [];
173
- },
174
- fix(context: LintContext): LintFix[] {
175
- // Optional: provide auto-fixes
176
- return [];
177
- }
178
- };
179
- ```
180
-
181
- ## Serializer Interface
182
-
183
- Implement lexicon-specific serialization:
184
-
185
- ```typescript
186
- import type { Serializer, Declarable } from "@intentius/chant";
187
-
188
- const mySerializer: Serializer = {
189
- name: "my-lexicon",
190
- rulePrefix: "ML",
191
- serialize(entities: Map<string, Declarable>): string {
192
- // Serialize entities to lexicon-specific format
193
- return JSON.stringify({ entities: Array.from(entities.keys()) });
194
- }
195
- };
196
- ```
197
-
198
- ## Utilities
199
-
200
- Helper functions for working with declarables:
201
-
202
- ```typescript
203
- import {
204
- getAttributes,
205
- getLogicalName,
206
- LOGICAL_NAME_SYMBOL
207
- } from "@intentius/chant";
208
-
209
- // Get attribute names that have AttrRef values
210
- const attrs = getAttributes(myEntity);
211
- // ["arn", "endpoint"]
212
-
213
- // Get the logical name assigned during discovery
214
- (entity as any)[LOGICAL_NAME_SYMBOL] = "MyResource";
215
- const name = getLogicalName(entity);
216
- // "MyResource"
217
- ```
218
-
219
- ## Lexicon Detection
220
-
221
- Automatically detect which lexicon is being used:
222
-
223
- ```typescript
224
- import { detectLexicon } from "@intentius/chant";
225
-
226
- const lexicon = await detectLexicon(["./src/infra/main.ts"]);
227
- // "aws" (currently the only supported lexicon)
228
- ```
229
-
230
- ## Template Import System
231
-
232
- Convert external templates to TypeScript:
233
-
234
- ```typescript
235
- import type {
236
- TemplateIR,
237
- TemplateParser,
238
- TypeScriptGenerator
239
- } from "@intentius/chant";
240
-
241
- // Parser converts external format to IR
242
- const parser: TemplateParser = {
243
- parse(content: string): TemplateIR {
244
- return { resources: [], parameters: [] };
245
- }
246
- };
247
-
248
- // Generator converts IR to TypeScript
249
- const generator: TypeScriptGenerator = {
250
- generate(ir: TemplateIR): GeneratedFile[] {
251
- return [{ path: "resources.ts", content: "..." }];
252
- }
253
- };
254
- ```
255
-
256
- ## Codegen Infrastructure
257
-
258
- Core provides reusable infrastructure for lexicon code generation pipelines. Lexicons supply provider-specific callbacks; core handles orchestration.
259
-
260
- ### Runtime Factories
261
-
262
- Create Declarable-marked constructors for generated resource and property types:
263
-
264
- ```typescript
265
- import { createResource, createProperty } from "@intentius/chant/runtime";
266
-
267
- // Creates a constructor that stamps out Declarable objects
268
- const MyResource = createResource("Provider::Service::Type", "my-lexicon", { arn: "Arn" });
269
- const MyProperty = createProperty("Provider::Service::Type.PropType", "my-lexicon");
9
+ ```bash
10
+ npm install --save-dev @intentius/chant @intentius/chant-lexicon-aws
270
11
  ```
271
12
 
272
- ### Naming Strategy
273
-
274
- Collision-free TypeScript class name generation, parameterized by data tables:
275
-
276
- ```typescript
277
- import { NamingStrategy, type NamingConfig } from "@intentius/chant/codegen/naming";
278
-
279
- const config: NamingConfig = {
280
- priorityNames: { "Provider::S3::Bucket": "Bucket" },
281
- priorityAliases: {},
282
- priorityPropertyAliases: {},
283
- serviceAbbreviations: { "ElasticLoadBalancingV2": "Elbv2" },
284
- shortName: (t) => t.split("::").pop()!,
285
- serviceName: (t) => t.split("::")[1],
286
- };
287
-
288
- const naming = new NamingStrategy(inputs, config);
289
- naming.resolve("Provider::S3::Bucket"); // "Bucket"
290
- ```
291
-
292
- ### Generation Pipeline
293
-
294
- Generic pipeline orchestration — step sequencing, logging, warning collection, stats counting:
295
-
296
- ```typescript
297
- import { generatePipeline, type GeneratePipelineConfig } from "@intentius/chant/codegen/generate";
298
-
299
- const config: GeneratePipelineConfig<MyParsedResult> = {
300
- fetchSchemas: async (opts) => { /* ... */ },
301
- parseSchema: (name, data) => { /* ... */ },
302
- createNaming: (results) => new MyNamingStrategy(results),
303
- generateRegistry: (results, naming) => { /* ... */ },
304
- generateTypes: (results, naming) => { /* ... */ },
305
- generateRuntimeIndex: (results, naming) => { /* ... */ },
306
- };
307
-
308
- const result = await generatePipeline(config, { verbose: true });
309
- ```
310
-
311
- ### Packaging Pipeline
312
-
313
- Bundles generation output into a distributable `BundleSpec`:
314
-
315
- ```typescript
316
- import { packagePipeline, type PackagePipelineConfig } from "@intentius/chant/codegen/package";
317
-
318
- const result = await packagePipeline({
319
- generate: (opts) => myGenerate(opts),
320
- buildManifest: (genResult) => ({ name: "my-lexicon", version: "1.0.0", /* ... */ }),
321
- srcDir: __dirname,
322
- collectSkills: () => new Map(),
323
- });
324
- ```
325
-
326
- ### Fetch Utilities
327
-
328
- HTTP fetch with local file caching and zip extraction:
329
-
330
- ```typescript
331
- import { fetchWithCache, extractFromZip } from "@intentius/chant/codegen/fetch";
332
-
333
- const data = await fetchWithCache({ url: "https://...", cacheFile: "/tmp/cache.zip" });
334
- const files = await extractFromZip(data, (name) => name.endsWith(".json"));
335
- ```
336
-
337
- ### LSP Providers
338
-
339
- Generic lexicon-based completion and hover:
340
-
341
- ```typescript
342
- import { LexiconIndex, lexiconCompletions, lexiconHover } from "@intentius/chant/lsp/lexicon-providers";
343
-
344
- const index = new LexiconIndex(lexiconData);
345
- const completions = lexiconCompletions(ctx, index, "My resource");
346
- const hover = lexiconHover(ctx, index);
347
- ```
348
-
349
- ## TypeScript Support
350
-
351
- This package is written in TypeScript and provides full type definitions.
352
-
353
- ## Documentation
354
-
355
- - [Core Concepts](../../docs/src/content/docs/guides/core-concepts.md) - Detailed guide on declarables, intrinsics, and the type system
356
- - [Testing Guide](../../TESTING.md) - Testing patterns and utilities
13
+ **[Documentation →](https://intentius.io/chant/getting-started/introduction/)**
357
14
 
358
15
  ## Related Packages
359
16
 
360
- - `@intentius/chant-lexicon-aws` - AWS CloudFormation lexicon
361
- - `@intentius/chant-test-utils` - Testing utilities
17
+ | Package | Role |
18
+ |---------|------|
19
+ | [@intentius/chant-lexicon-aws](https://www.npmjs.com/package/@intentius/chant-lexicon-aws) | AWS CloudFormation lexicon |
20
+ | [@intentius/chant-lexicon-gitlab](https://www.npmjs.com/package/@intentius/chant-lexicon-gitlab) | GitLab CI lexicon |
362
21
 
363
22
  ## License
364
23
 
package/bin/chant ADDED
@@ -0,0 +1,20 @@
1
+ #!/bin/sh
2
+ # Cross-runtime CLI wrapper. Tries bun first, falls back to npx tsx.
3
+ set -e
4
+
5
+ # Resolve symlinks to find the real script location
6
+ SELF="$0"
7
+ while [ -L "$SELF" ]; do
8
+ DIR="$(cd "$(dirname "$SELF")" && pwd)"
9
+ SELF="$(readlink "$SELF")"
10
+ # Handle relative symlink targets
11
+ case "$SELF" in /*) ;; *) SELF="$DIR/$SELF" ;; esac
12
+ done
13
+ SCRIPT_DIR="$(cd "$(dirname "$SELF")" && pwd)"
14
+ MAIN_TS="$SCRIPT_DIR/../src/cli/main.ts"
15
+
16
+ if command -v bun >/dev/null 2>&1; then
17
+ exec bun "$MAIN_TS" "$@"
18
+ else
19
+ exec npx tsx "$MAIN_TS" "$@"
20
+ fi
package/package.json CHANGED
@@ -1,23 +1,24 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.0.4",
3
+ "version": "0.0.8",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
- "files": ["src/"],
6
+ "files": ["src/", "bin/"],
7
7
  "publishConfig": {
8
- "access": "public"
9
- },
10
- "bin": {
11
- "chant": "./src/cli/main.ts"
12
- },
13
- "exports": {
14
- ".": "./src/index.ts",
15
- "./cli": "./src/cli/index.ts",
16
- "./cli/*": "./src/cli/*",
17
- "./*": "./src/*"
18
- },
19
- "dependencies": {
20
- "fflate": "^0.8.2",
21
- "zod": "^4.3.6"
22
- }
8
+ "access": "public"
9
+ },
10
+ "bin": {
11
+ "chant": "./bin/chant"
12
+ },
13
+ "exports": {
14
+ ".": "./src/index.ts",
15
+ "./cli": "./src/cli/index.ts",
16
+ "./cli/*": "./src/cli/*",
17
+ "./*": "./src/*"
18
+ },
19
+ "dependencies": {
20
+ "fflate": "^0.8.2",
21
+ "picomatch": "^4.0.3",
22
+ "zod": "^4.3.6"
23
+ }
23
24
  }
package/src/bench.test.ts CHANGED
@@ -6,60 +6,9 @@ import { discover } from "./discovery/index";
6
6
  import { runLint } from "./lint/engine";
7
7
  import { build } from "./build";
8
8
  import type { Serializer } from "./serializer";
9
- import type { LintRule } from "./lint/rule";
10
-
11
- // Import all core lint rules
12
- import {
13
- flatDeclarationsRule,
14
- exportRequiredRule,
15
- fileDeclarableLimitRule,
16
- singleConcernFileRule,
17
- preferNamespaceImportRule,
18
- barrelImportStyleRule,
19
- declarableNamingConventionRule,
20
- noUnusedDeclarableImportRule,
21
- noRedundantValueCastRule,
22
- noUnusedDeclarableRule,
23
- noCyclicDeclarableRefRule,
24
- noRedundantTypeImportRule,
25
- noStringRefRule,
26
- enforceBarrelImportRule,
27
- enforceBarrelRefRule,
28
- evl001NonLiteralExpressionRule,
29
- evl002ControlFlowResourceRule,
30
- evl003DynamicPropertyAccessRule,
31
- evl004SpreadNonConstRule,
32
- evl005ResourceBlockBodyRule,
33
- evl006BarrelUsageRule,
34
- evl007InvalidSiblingsRule,
35
- evl008UnresolvableBarrelRefRule,
36
- } from "./lint/rules/index";
37
-
38
- const coreRules: LintRule[] = [
39
- flatDeclarationsRule,
40
- exportRequiredRule,
41
- fileDeclarableLimitRule,
42
- singleConcernFileRule,
43
- preferNamespaceImportRule,
44
- barrelImportStyleRule,
45
- declarableNamingConventionRule,
46
- noUnusedDeclarableImportRule,
47
- noRedundantValueCastRule,
48
- noUnusedDeclarableRule,
49
- noCyclicDeclarableRefRule,
50
- noRedundantTypeImportRule,
51
- noStringRefRule,
52
- enforceBarrelImportRule,
53
- enforceBarrelRefRule,
54
- evl001NonLiteralExpressionRule,
55
- evl002ControlFlowResourceRule,
56
- evl003DynamicPropertyAccessRule,
57
- evl004SpreadNonConstRule,
58
- evl005ResourceBlockBodyRule,
59
- evl006BarrelUsageRule,
60
- evl007InvalidSiblingsRule,
61
- evl008UnresolvableBarrelRefRule,
62
- ];
9
+ import { loadCoreRules } from "./lint/rules/index";
10
+
11
+ const coreRules = loadCoreRules();
63
12
 
64
13
  interface FixtureSize {
65
14
  name: string;
@@ -19,7 +19,9 @@ export const fixturePlugin: LexiconPlugin = {
19
19
 
20
20
  async validate(options?: { verbose?: boolean }): Promise<void> {
21
21
  const { validate } = await import("./validate");
22
- await validate(options);
22
+ const { printValidationResult } = await import("@intentius/chant/codegen/validate");
23
+ const result = await validate();
24
+ printValidationResult(result);
23
25
  },
24
26
 
25
27
  async coverage(options?: { verbose?: boolean; minOverall?: number }): Promise<void> {
@@ -29,32 +31,15 @@ export const fixturePlugin: LexiconPlugin = {
29
31
 
30
32
  async package(options?: { verbose?: boolean; force?: boolean }): Promise<void> {
31
33
  const { packageLexicon } = await import("./codegen/package");
32
- await packageLexicon(options);
33
- },
34
-
35
- async rollback(options?: { restore?: string; verbose?: boolean }): Promise<void> {
36
- const { listSnapshots, restoreSnapshot } = await import("./codegen/rollback");
34
+ const { writeBundleSpec } = await import("@intentius/chant/codegen/package");
37
35
  const { join, dirname } = await import("path");
38
36
  const { fileURLToPath } = await import("url");
39
37
 
38
+ const { spec, stats } = await packageLexicon(options);
40
39
  const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
41
- const snapshotsDir = join(pkgDir, ".snapshots");
42
-
43
- if (options?.restore) {
44
- const generatedDir = join(pkgDir, "src", "generated");
45
- restoreSnapshot(String(options.restore), generatedDir);
46
- console.error(`Restored snapshot: ${options.restore}`);
47
- } else {
48
- const snapshots = listSnapshots(snapshotsDir);
49
- if (snapshots.length === 0) {
50
- console.error("No snapshots available.");
51
- } else {
52
- console.error(`Available snapshots (${snapshots.length}):`);
53
- for (const s of snapshots) {
54
- console.error(` ${s.timestamp} ${s.resources} resources ${s.path}`);
55
- }
56
- }
57
- }
40
+ writeBundleSpec(spec, join(pkgDir, "dist"));
41
+
42
+ console.error(`Packaged ${stats.resources} resources, ${stats.ruleCount} rules, ${stats.skillCount} skills`);
58
43
  },
59
44
 
60
45
  // ── Optional extensions (uncomment and implement as needed) ───
@@ -1,24 +1,28 @@
1
1
  /**
2
- * Validate generated artifacts for the fixture lexicon.
2
+ * Validate generated lexicon-fixture artifacts.
3
3
  *
4
- * TODO: Add validation checks for your generated files.
4
+ * Thin wrapper around the core validation framework
5
+ * with fixture-specific configuration.
5
6
  */
6
- export async function validate(options?: { verbose?: boolean }): Promise<void> {
7
- const checks = [
8
- // TODO: Add checks — e.g. verify lexicon JSON exists, types compile,
9
- // registry has expected resources, etc.
10
- { name: "placeholder", ok: true, error: undefined as string | undefined },
11
- ];
12
7
 
13
- for (const check of checks) {
14
- const status = check.ok ? "OK" : "FAIL";
15
- const msg = check.error ? ` — ${check.error}` : "";
16
- console.error(` [${status}] ${check.name}${msg}`);
17
- }
8
+ import { dirname } from "path";
9
+ import { fileURLToPath } from "url";
10
+ import { validateLexiconArtifacts, type ValidateResult } from "@intentius/chant/codegen/validate";
18
11
 
19
- const failed = checks.filter((c) => !c.ok);
20
- if (failed.length > 0) {
21
- throw new Error("Validation failed");
22
- }
23
- console.error("All validation checks passed.");
12
+ export type { ValidateCheck, ValidateResult } from "@intentius/chant/codegen/validate";
13
+
14
+ // TODO: Add names of required entities for your lexicon
15
+ const REQUIRED_NAMES: string[] = [];
16
+
17
+ /**
18
+ * Validate the generated lexicon-fixture artifacts.
19
+ */
20
+ export async function validate(opts?: { basePath?: string }): Promise<ValidateResult> {
21
+ const basePath = opts?.basePath ?? dirname(dirname(fileURLToPath(import.meta.url)));
22
+
23
+ return validateLexiconArtifacts({
24
+ lexiconJsonFilename: "lexicon-fixture.json",
25
+ requiredNames: REQUIRED_NAMES,
26
+ basePath,
27
+ });
24
28
  }
@@ -129,7 +129,9 @@ export const fixturePlugin: LexiconPlugin = {
129
129
 
130
130
  async validate(options?: { verbose?: boolean }): Promise<void> {
131
131
  const { validate } = await import("./validate");
132
- await validate(options);
132
+ const { printValidationResult } = await import("@intentius/chant/codegen/validate");
133
+ const result = await validate();
134
+ printValidationResult(result);
133
135
  },
134
136
 
135
137
  async coverage(options?: { verbose?: boolean; minOverall?: number }): Promise<void> {
@@ -139,32 +141,15 @@ export const fixturePlugin: LexiconPlugin = {
139
141
 
140
142
  async package(options?: { verbose?: boolean; force?: boolean }): Promise<void> {
141
143
  const { packageLexicon } = await import("./codegen/package");
142
- await packageLexicon(options);
143
- },
144
-
145
- async rollback(options?: { restore?: string; verbose?: boolean }): Promise<void> {
146
- const { listSnapshots, restoreSnapshot } = await import("./codegen/rollback");
144
+ const { writeBundleSpec } = await import("@intentius/chant/codegen/package");
147
145
  const { join, dirname } = await import("path");
148
146
  const { fileURLToPath } = await import("url");
149
147
 
148
+ const { spec, stats } = await packageLexicon(options);
150
149
  const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
151
- const snapshotsDir = join(pkgDir, ".snapshots");
152
-
153
- if (options?.restore) {
154
- const generatedDir = join(pkgDir, "src", "generated");
155
- restoreSnapshot(String(options.restore), generatedDir);
156
- console.error(\`Restored snapshot: \${options.restore}\`);
157
- } else {
158
- const snapshots = listSnapshots(snapshotsDir);
159
- if (snapshots.length === 0) {
160
- console.error("No snapshots available.");
161
- } else {
162
- console.error(\`Available snapshots (\${snapshots.length}):\`);
163
- for (const s of snapshots) {
164
- console.error(\` \${s.timestamp} \${s.resources} resources \${s.path}\`);
165
- }
166
- }
167
- }
150
+ writeBundleSpec(spec, join(pkgDir, "dist"));
151
+
152
+ console.error(\`Packaged \${stats.resources} resources, \${stats.ruleCount} rules, \${stats.skillCount} skills\`);
168
153
  },
169
154
 
170
155
  // ── Optional extensions (uncomment and implement as needed) ───
@@ -5,7 +5,7 @@ import { runPostSynthChecks } from "../../lint/post-synth";
5
5
  import type { PostSynthCheck } from "../../lint/post-synth";
6
6
  import { formatError, formatWarning, formatSuccess, formatBold, formatInfo } from "../format";
7
7
  import { writeFileSync } from "fs";
8
- import { resolve } from "path";
8
+ import { resolve, dirname, join } from "path";
9
9
  import { watchDirectory, formatTimestamp, formatChangedFiles } from "../watch";
10
10
 
11
11
  /**
@@ -172,7 +172,6 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
172
172
 
173
173
  // Write additional files (e.g. nested stack templates) alongside the primary output
174
174
  if (additionalFiles.size > 0) {
175
- const { dirname, join } = require("path");
176
175
  const outputDir = dirname(outputPath);
177
176
  for (const [filename, content] of additionalFiles) {
178
177
  let fileContent = content;
@@ -52,7 +52,7 @@ describe("importCommand", () => {
52
52
  expect(result.lexicon).toBe("aws");
53
53
  expect(result.generatedFiles.length).toBeGreaterThan(0);
54
54
  expect(existsSync(outputDir)).toBe(true);
55
- });
55
+ }, 15000);
56
56
 
57
57
  test("imports CloudFormation template with multiple resources", async () => {
58
58
  const template = {