@intentius/chant 0.0.18 → 0.0.24
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.
- package/bin/chant +4 -1
- package/package.json +20 -1
- package/src/build.test.ts +4 -2
- package/src/build.ts +3 -0
- package/src/builder.test.ts +3 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/astro.config.mjs +0 -3
- package/src/cli/commands/build.ts +5 -12
- package/src/cli/commands/diff.test.ts +2 -1
- package/src/cli/commands/diff.ts +2 -1
- package/src/cli/commands/init-lexicon/templates/codegen.ts +188 -0
- package/src/cli/commands/init-lexicon/templates/docs.ts +81 -0
- package/src/cli/commands/init-lexicon/templates/examples.ts +35 -0
- package/src/cli/commands/init-lexicon/templates/lint.ts +30 -0
- package/src/cli/commands/init-lexicon/templates/lsp.ts +39 -0
- package/src/cli/commands/init-lexicon/templates/plugin.ts +110 -0
- package/src/cli/commands/init-lexicon/templates/project.ts +182 -0
- package/src/cli/commands/init-lexicon/templates/spec.ts +57 -0
- package/src/cli/commands/init-lexicon/templates/tests.ts +70 -0
- package/src/cli/commands/init-lexicon.test.ts +0 -9
- package/src/cli/commands/init-lexicon.ts +12 -868
- package/src/cli/commands/init.ts +2 -20
- package/src/cli/conflict-check.test.ts +43 -0
- package/src/cli/handlers/build.ts +3 -3
- package/src/cli/handlers/lint.ts +2 -2
- package/src/cli/handlers/spell.ts +396 -0
- package/src/cli/handlers/state.ts +230 -0
- package/src/cli/lsp/server.test.ts +4 -0
- package/src/cli/main.ts +37 -3
- package/src/cli/mcp/resource-handlers.ts +227 -0
- package/src/cli/mcp/server.test.ts +13 -9
- package/src/cli/mcp/server.ts +24 -199
- package/src/cli/mcp/state-tools.ts +138 -0
- package/src/cli/mcp/tools/build.ts +2 -1
- package/src/cli/mcp/types.ts +45 -0
- package/src/cli/plugins.ts +1 -1
- package/src/cli/reporters/stylish.test.ts +2 -2
- package/src/cli/reporters/stylish.ts +1 -1
- package/src/codegen/docs-file-markers.ts +69 -0
- package/src/codegen/docs-rule-scanning.ts +159 -0
- package/src/codegen/docs-sections.ts +159 -0
- package/src/codegen/docs-sidebar.ts +56 -0
- package/src/codegen/docs-types.ts +79 -0
- package/src/codegen/docs.ts +9 -495
- package/src/composite.test.ts +76 -1
- package/src/composite.ts +37 -0
- package/src/config.ts +4 -0
- package/src/declarable.test.ts +2 -1
- package/src/declarable.ts +1 -1
- package/src/discovery/collect.test.ts +34 -0
- package/src/discovery/collect.ts +12 -0
- package/src/discovery/graph.test.ts +40 -0
- package/src/discovery/import.test.ts +5 -5
- package/src/discovery/resolve.test.ts +20 -0
- package/src/discovery/resolve.ts +2 -2
- package/src/index.ts +2 -0
- package/src/lexicon-plugin-helpers.ts +130 -0
- package/src/lexicon.ts +24 -0
- package/src/lint/rule-options.test.ts +3 -3
- package/src/lint/rule-registry.test.ts +1 -1
- package/src/lint/rules/composite-scope.ts +1 -1
- package/src/serializer-walker.ts +2 -1
- package/src/spell/discovery.ts +183 -0
- package/src/spell/index.ts +3 -0
- package/src/spell/prompt.ts +133 -0
- package/src/spell/types.ts +89 -0
- package/src/state/digest.ts +88 -0
- package/src/state/git.ts +317 -0
- package/src/state/index.ts +4 -0
- package/src/state/snapshot.ts +179 -0
- package/src/state/types.ts +59 -0
- package/src/toml-emit.ts +182 -0
- package/src/toml-parse.ts +370 -0
- package/src/toml-utils.ts +60 -0
- package/src/toml.ts +5 -602
- package/src/types.ts +2 -1
- package/src/utils.test.ts +16 -3
- package/src/utils.ts +31 -1
- package/src/validation.test.ts +11 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content/docs/getting-started.mdx +0 -6
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content/docs/lint-rules.mdx +0 -6
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content/docs/serialization.mdx +0 -6
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/actions/.gitkeep +0 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/composites/.gitkeep +0 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/coverage.ts +0 -11
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/import/generator.ts +0 -10
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/import/parser.ts +0 -10
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/lint/post-synth/.gitkeep +0 -0
package/bin/chant
CHANGED
|
@@ -15,6 +15,9 @@ MAIN_TS="$SCRIPT_DIR/../src/cli/main.ts"
|
|
|
15
15
|
|
|
16
16
|
if command -v bun >/dev/null 2>&1; then
|
|
17
17
|
exec bun "$MAIN_TS" "$@"
|
|
18
|
-
|
|
18
|
+
elif command -v npx >/dev/null 2>&1; then
|
|
19
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
|
|
20
23
|
fi
|
package/package.json
CHANGED
|
@@ -1,7 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
|
+
"description": "Declarative infrastructure-as-code toolkit — TypeScript on Bun",
|
|
4
5
|
"license": "Apache-2.0",
|
|
6
|
+
"homepage": "https://intentius.io/chant",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/intentius/chant.git",
|
|
10
|
+
"directory": "packages/core"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/intentius/chant/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"infrastructure-as-code",
|
|
17
|
+
"iac",
|
|
18
|
+
"typescript",
|
|
19
|
+
"declarative",
|
|
20
|
+
"cloudformation",
|
|
21
|
+
"aws",
|
|
22
|
+
"devops"
|
|
23
|
+
],
|
|
5
24
|
"type": "module",
|
|
6
25
|
"files": [
|
|
7
26
|
"src/",
|
package/src/build.test.ts
CHANGED
|
@@ -189,10 +189,12 @@ export const betaEntity = {
|
|
|
189
189
|
expect(result.outputs.has("alpha")).toBe(true);
|
|
190
190
|
expect(result.outputs.has("beta")).toBe(true);
|
|
191
191
|
|
|
192
|
-
const
|
|
192
|
+
const alphaRaw = result.outputs.get("alpha")!;
|
|
193
|
+
const alphaOutput = JSON.parse(typeof alphaRaw === "string" ? alphaRaw : alphaRaw.primary);
|
|
193
194
|
expect(alphaOutput.alpha).toContain("alphaEntity");
|
|
194
195
|
|
|
195
|
-
const
|
|
196
|
+
const betaRaw = result.outputs.get("beta")!;
|
|
197
|
+
const betaOutput = JSON.parse(typeof betaRaw === "string" ? betaRaw : betaRaw.primary);
|
|
196
198
|
expect(betaOutput.beta).toContain("betaEntity");
|
|
197
199
|
});
|
|
198
200
|
|
package/src/build.ts
CHANGED
|
@@ -29,6 +29,8 @@ export interface BuildResult {
|
|
|
29
29
|
outputs: Map<string, string | SerializerResult>;
|
|
30
30
|
/** Map of entity name to Declarable entity */
|
|
31
31
|
entities: Map<string, Declarable>;
|
|
32
|
+
/** Resource-level dependency graph from discovery */
|
|
33
|
+
dependencies: Map<string, Set<string>>;
|
|
32
34
|
/** Array of warnings encountered during the build */
|
|
33
35
|
warnings: string[];
|
|
34
36
|
/** Array of errors encountered during discovery and build */
|
|
@@ -430,6 +432,7 @@ export async function build(
|
|
|
430
432
|
return {
|
|
431
433
|
outputs,
|
|
432
434
|
entities: discoveryResult.entities,
|
|
435
|
+
dependencies: discoveryResult.dependencies,
|
|
433
436
|
warnings,
|
|
434
437
|
errors,
|
|
435
438
|
manifest,
|
package/src/builder.test.ts
CHANGED
|
@@ -36,6 +36,7 @@ class SimpleResourceBuilder extends Builder<TestResource> {
|
|
|
36
36
|
throw new Error("Name and type are required");
|
|
37
37
|
}
|
|
38
38
|
return {
|
|
39
|
+
lexicon: "test",
|
|
39
40
|
entityType: "TestResource",
|
|
40
41
|
[DECLARABLE_MARKER]: true,
|
|
41
42
|
name: this.name,
|
|
@@ -72,6 +73,7 @@ class ValidatedResourceBuilder extends Builder<TestResource> {
|
|
|
72
73
|
throw new Error("Name and type are required");
|
|
73
74
|
}
|
|
74
75
|
return {
|
|
76
|
+
lexicon: "test",
|
|
75
77
|
entityType: "TestResource",
|
|
76
78
|
[DECLARABLE_MARKER]: true,
|
|
77
79
|
name: this.name,
|
|
@@ -103,6 +105,7 @@ class DefaultsResourceBuilder extends Builder<TestResource> {
|
|
|
103
105
|
|
|
104
106
|
build(): TestResource {
|
|
105
107
|
return {
|
|
108
|
+
lexicon: "test",
|
|
106
109
|
entityType: "TestResource",
|
|
107
110
|
[DECLARABLE_MARKER]: true,
|
|
108
111
|
name: this.name,
|
|
@@ -8,9 +8,6 @@ export default defineConfig({
|
|
|
8
8
|
title: 'Fixture',
|
|
9
9
|
sidebar: [
|
|
10
10
|
{ label: 'Overview', slug: '' },
|
|
11
|
-
{ label: 'Getting Started', slug: 'getting-started' },
|
|
12
|
-
{ label: 'Serialization', slug: 'serialization' },
|
|
13
|
-
{ label: 'Lint Rules', slug: 'lint-rules' },
|
|
14
11
|
],
|
|
15
12
|
}),
|
|
16
13
|
],
|
|
@@ -3,6 +3,7 @@ import type { Serializer, SerializerResult } from "../../serializer";
|
|
|
3
3
|
import type { LexiconPlugin } from "../../lexicon";
|
|
4
4
|
import { runPostSynthChecks } from "../../lint/post-synth";
|
|
5
5
|
import type { PostSynthCheck } from "../../lint/post-synth";
|
|
6
|
+
import { sortedJsonReplacer } from "../../utils";
|
|
6
7
|
import { formatError, formatWarning, formatSuccess, formatBold, formatInfo } from "../format";
|
|
7
8
|
import { writeFileSync } from "fs";
|
|
8
9
|
import { resolve, dirname, join } from "path";
|
|
@@ -214,6 +215,10 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
|
|
|
214
215
|
const resourceCount = result.entities.size;
|
|
215
216
|
const fileCount = result.sourceFileCount;
|
|
216
217
|
|
|
218
|
+
if (fileCount === 0 && errors.length === 0) {
|
|
219
|
+
console.error(formatInfo("No source files found — create .ts files in the target directory"));
|
|
220
|
+
}
|
|
221
|
+
|
|
217
222
|
if (options.verbose && errors.length === 0) {
|
|
218
223
|
console.error(
|
|
219
224
|
formatSuccess(
|
|
@@ -231,18 +236,6 @@ export async function buildCommand(options: BuildOptions): Promise<BuildResult>
|
|
|
231
236
|
};
|
|
232
237
|
}
|
|
233
238
|
|
|
234
|
-
/**
|
|
235
|
-
* JSON.stringify replacer that sorts object keys for deterministic output
|
|
236
|
-
*/
|
|
237
|
-
function sortedJsonReplacer(_key: string, value: unknown): unknown {
|
|
238
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
239
|
-
return Object.fromEntries(
|
|
240
|
-
Object.entries(value as Record<string, unknown>).sort(([a], [b]) => a.localeCompare(b))
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
return value;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
239
|
/**
|
|
247
240
|
* Simple JSON to YAML converter
|
|
248
241
|
*/
|
|
@@ -86,7 +86,8 @@ export const myBucket = {
|
|
|
86
86
|
const combined: Record<string, unknown> = {};
|
|
87
87
|
const sortedSerializerNames = [...buildResult.outputs.keys()].sort();
|
|
88
88
|
for (const serializerName of sortedSerializerNames) {
|
|
89
|
-
|
|
89
|
+
const raw = buildResult.outputs.get(serializerName)!;
|
|
90
|
+
combined[serializerName] = JSON.parse(typeof raw === "string" ? raw : raw.primary);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
// Sort keys to match diffCommand behavior
|
package/src/cli/commands/diff.ts
CHANGED
|
@@ -46,7 +46,8 @@ export async function diffCommand(options: DiffOptions): Promise<DiffResult> {
|
|
|
46
46
|
const combined: Record<string, unknown> = {};
|
|
47
47
|
const sortedLexiconNames = [...result.outputs.keys()].sort();
|
|
48
48
|
for (const lexiconName of sortedLexiconNames) {
|
|
49
|
-
|
|
49
|
+
const raw = result.outputs.get(lexiconName)!;
|
|
50
|
+
combined[lexiconName] = JSON.parse(typeof raw === "string" ? raw : raw.primary);
|
|
50
51
|
}
|
|
51
52
|
const currentOutput = JSON.stringify(combined, sortedJsonReplacer, 2);
|
|
52
53
|
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegen template generators for init-lexicon scaffold.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function generateCodegenGenerateTs(): string {
|
|
6
|
+
return `import { generatePipeline, writeGeneratedArtifacts } from "@intentius/chant/codegen/generate";
|
|
7
|
+
import type { GenerateResult } from "@intentius/chant/codegen/generate";
|
|
8
|
+
import { dirname } from "path";
|
|
9
|
+
import { fileURLToPath } from "url";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Run the code generation pipeline.
|
|
13
|
+
*
|
|
14
|
+
* Each callback has a TODO describing what to implement.
|
|
15
|
+
*/
|
|
16
|
+
export async function generate(options?: { verbose?: boolean }): Promise<GenerateResult> {
|
|
17
|
+
const result = await generatePipeline({
|
|
18
|
+
// Must return Map<typeName, Buffer> — each entry is one schema file.
|
|
19
|
+
// Example: fetch a zip, extract JSON files, key by type name.
|
|
20
|
+
// See lexicons/aws/src/spec/fetch.ts for a working example.
|
|
21
|
+
fetchSchemas: async (opts) => {
|
|
22
|
+
throw new Error("TODO: implement fetchSchemas — download your upstream spec");
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
// Must return a ParsedResult (with propertyTypes[] and enums[] at minimum).
|
|
26
|
+
// Return null to skip a schema file.
|
|
27
|
+
// See lexicons/aws/src/spec/parse.ts for a working example.
|
|
28
|
+
parseSchema: (name, data) => {
|
|
29
|
+
throw new Error("TODO: implement parseSchema — parse a single schema file");
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
// Must return a NamingStrategy instance.
|
|
33
|
+
// See lexicons/aws/src/codegen/naming.ts and ./naming.ts for setup.
|
|
34
|
+
createNaming: (results) => {
|
|
35
|
+
throw new Error("TODO: implement createNaming — return a NamingStrategy instance");
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
// Must return a string of JSON (the lexicon registry).
|
|
39
|
+
// Use buildRegistry + serializeRegistry from @intentius/chant/codegen/generate-registry.
|
|
40
|
+
// See lexicons/aws/src/codegen/generate.ts for a working example.
|
|
41
|
+
generateRegistry: (results, naming) => {
|
|
42
|
+
throw new Error("TODO: implement generateRegistry — produce lexicon JSON");
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
// Must return a string of TypeScript declarations (.d.ts content).
|
|
46
|
+
// See lexicons/aws/src/codegen/generate.ts for a working example.
|
|
47
|
+
generateTypes: (results, naming) => {
|
|
48
|
+
throw new Error("TODO: implement generateTypes — produce .d.ts content");
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
// Must return a string of TypeScript (runtime index with factory exports).
|
|
52
|
+
// Use generateRuntimeIndex from @intentius/chant/codegen/generate-runtime-index.
|
|
53
|
+
// See lexicons/aws/src/codegen/generate.ts for a working example.
|
|
54
|
+
generateRuntimeIndex: (results, naming) => {
|
|
55
|
+
throw new Error("TODO: implement generateRuntimeIndex — produce index.ts content");
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (options?.verbose) {
|
|
60
|
+
console.error(\`Generated \${result.resources} resources, \${result.properties} property types\`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Write generated files to the package directory.
|
|
68
|
+
*/
|
|
69
|
+
export function writeGeneratedFiles(result: GenerateResult, pkgDir?: string): void {
|
|
70
|
+
const dir = pkgDir ?? dirname(dirname(fileURLToPath(import.meta.url)));
|
|
71
|
+
writeGeneratedArtifacts({
|
|
72
|
+
baseDir: dir,
|
|
73
|
+
files: {
|
|
74
|
+
"lexicon.json": result.lexiconJSON,
|
|
75
|
+
"index.d.ts": result.typesDTS,
|
|
76
|
+
"index.ts": result.indexTS,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function generateCodegenGenerateCliTs(): string {
|
|
84
|
+
return `#!/usr/bin/env bun
|
|
85
|
+
import { generate, writeGeneratedFiles } from "./generate";
|
|
86
|
+
import { dirname } from "path";
|
|
87
|
+
import { fileURLToPath } from "url";
|
|
88
|
+
|
|
89
|
+
const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
90
|
+
const result = await generate({ verbose: true });
|
|
91
|
+
writeGeneratedFiles(result, pkgDir);
|
|
92
|
+
`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function generateCodegenNamingTs(): string {
|
|
96
|
+
return `import { NamingStrategy, type NamingConfig, type NamingInput } from "@intentius/chant/codegen/naming";
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Naming configuration for this lexicon.
|
|
100
|
+
*
|
|
101
|
+
* TODO: Populate these tables with your provider's naming conventions.
|
|
102
|
+
*/
|
|
103
|
+
export const namingConfig: NamingConfig = {
|
|
104
|
+
// High-priority short names for common resource types
|
|
105
|
+
priorityNames: {},
|
|
106
|
+
|
|
107
|
+
// Aliases for resource types that need alternate names
|
|
108
|
+
priorityAliases: {},
|
|
109
|
+
|
|
110
|
+
// Aliases for property types
|
|
111
|
+
priorityPropertyAliases: {},
|
|
112
|
+
|
|
113
|
+
// Abbreviations for service names (used in collision resolution)
|
|
114
|
+
serviceAbbreviations: {},
|
|
115
|
+
|
|
116
|
+
// Extract the short name from a fully-qualified type string
|
|
117
|
+
shortName: (typeName: string) => typeName.split("::").pop()!,
|
|
118
|
+
|
|
119
|
+
// Extract the service name from a fully-qualified type string
|
|
120
|
+
serviceName: (typeName: string) => typeName.split("::")[1] ?? typeName,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Create a NamingStrategy instance from parsed results.
|
|
125
|
+
*/
|
|
126
|
+
export function createNaming(inputs: NamingInput[]): NamingStrategy {
|
|
127
|
+
return new NamingStrategy(inputs, namingConfig);
|
|
128
|
+
}
|
|
129
|
+
`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function generateCodegenPackageTs(name: string): string {
|
|
133
|
+
return `import { packagePipeline } from "@intentius/chant/codegen/package";
|
|
134
|
+
import type { PackagePipelineConfig } from "@intentius/chant/codegen/package";
|
|
135
|
+
import { generate } from "./generate";
|
|
136
|
+
import { dirname } from "path";
|
|
137
|
+
import { fileURLToPath } from "url";
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Package the ${name} lexicon for distribution.
|
|
141
|
+
*/
|
|
142
|
+
export async function packageLexicon(options?: { verbose?: boolean; force?: boolean }) {
|
|
143
|
+
const srcDir = dirname(fileURLToPath(import.meta.url));
|
|
144
|
+
|
|
145
|
+
const { spec, stats } = await packagePipeline({
|
|
146
|
+
generate: (opts) => generate({ verbose: opts?.verbose, force: opts?.force }),
|
|
147
|
+
buildManifest: (genResult) => ({
|
|
148
|
+
name: "${name}",
|
|
149
|
+
version: "0.0.1",
|
|
150
|
+
}),
|
|
151
|
+
srcDir,
|
|
152
|
+
collectSkills: () => new Map(),
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
console.error(\`Packaged \${stats.resources} resources, \${stats.ruleCount} rules\`);
|
|
156
|
+
return { spec, stats };
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function generateCodegenDocsTs(name: string): string {
|
|
162
|
+
return `import { docsPipeline, writeDocsSite } from "@intentius/chant/codegen/docs";
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Generate documentation site for the ${name} lexicon.
|
|
166
|
+
*/
|
|
167
|
+
export async function generateDocs(options?: { verbose?: boolean }): Promise<void> {
|
|
168
|
+
const config = {
|
|
169
|
+
name: "${name}",
|
|
170
|
+
displayName: "${name.charAt(0).toUpperCase() + name.slice(1)}",
|
|
171
|
+
description: "${name} lexicon documentation",
|
|
172
|
+
distDir: "./dist",
|
|
173
|
+
outDir: "./docs",
|
|
174
|
+
// TODO: Implement service grouping for your provider
|
|
175
|
+
serviceFromType: (type: string) => type.split("::")[1] ?? type,
|
|
176
|
+
// TODO: Implement resource documentation URLs
|
|
177
|
+
resourceTypeUrl: (type: string) => \`#\${type}\`,
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const result = docsPipeline(config);
|
|
181
|
+
writeDocsSite(config, result);
|
|
182
|
+
|
|
183
|
+
if (options?.verbose) {
|
|
184
|
+
console.error("Documentation generated");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
`;
|
|
188
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docs site template generators for init-lexicon scaffold.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function generateDocsPackageJson(name: string): string {
|
|
6
|
+
return JSON.stringify(
|
|
7
|
+
{
|
|
8
|
+
name: `@intentius/chant-lexicon-${name}-docs`,
|
|
9
|
+
type: "module",
|
|
10
|
+
version: "0.0.1",
|
|
11
|
+
private: true,
|
|
12
|
+
scripts: {
|
|
13
|
+
dev: "astro dev",
|
|
14
|
+
build: "astro build",
|
|
15
|
+
preview: "astro preview",
|
|
16
|
+
},
|
|
17
|
+
dependencies: {
|
|
18
|
+
"@astrojs/starlight": "^0.37.6",
|
|
19
|
+
astro: "^5.6.1",
|
|
20
|
+
sharp: "^0.34.2",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
null,
|
|
24
|
+
2,
|
|
25
|
+
) + "\n";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function generateDocsTsConfig(): string {
|
|
29
|
+
return JSON.stringify(
|
|
30
|
+
{
|
|
31
|
+
extends: "astro/tsconfigs/strict",
|
|
32
|
+
include: [".astro/types.d.ts", "**/*"],
|
|
33
|
+
exclude: ["dist"],
|
|
34
|
+
},
|
|
35
|
+
null,
|
|
36
|
+
2,
|
|
37
|
+
) + "\n";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function generateDocsAstroConfig(name: string): string {
|
|
41
|
+
const displayName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
42
|
+
return `// @ts-check
|
|
43
|
+
import { defineConfig } from 'astro/config';
|
|
44
|
+
import starlight from '@astrojs/starlight';
|
|
45
|
+
|
|
46
|
+
export default defineConfig({
|
|
47
|
+
integrations: [
|
|
48
|
+
starlight({
|
|
49
|
+
title: '${displayName}',
|
|
50
|
+
sidebar: [
|
|
51
|
+
{ label: 'Overview', slug: '' },
|
|
52
|
+
],
|
|
53
|
+
}),
|
|
54
|
+
],
|
|
55
|
+
});
|
|
56
|
+
`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function generateDocsContentConfig(): string {
|
|
60
|
+
return `import { defineCollection } from 'astro:content';
|
|
61
|
+
import { docsLoader } from '@astrojs/starlight/loaders';
|
|
62
|
+
import { docsSchema } from '@astrojs/starlight/schema';
|
|
63
|
+
|
|
64
|
+
export const collections = {
|
|
65
|
+
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
|
|
66
|
+
};
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function generateDocsIndexMdx(name: string): string {
|
|
71
|
+
const displayName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
72
|
+
return `---
|
|
73
|
+
title: Overview
|
|
74
|
+
description: ${displayName} lexicon for chant
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
Welcome to the ${displayName} lexicon documentation.
|
|
78
|
+
|
|
79
|
+
Run \`just generate\` to populate this site with generated reference pages.
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example template generators for init-lexicon scaffold.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function generateExamplePackageJson(name: string): string {
|
|
6
|
+
return JSON.stringify(
|
|
7
|
+
{
|
|
8
|
+
name: `@intentius/chant-lexicon-${name}-example-getting-started`,
|
|
9
|
+
version: "0.0.1",
|
|
10
|
+
private: true,
|
|
11
|
+
dependencies: {
|
|
12
|
+
[`@intentius/chant-lexicon-${name}`]: "workspace:*",
|
|
13
|
+
"@intentius/chant": "workspace:*",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
null,
|
|
17
|
+
2,
|
|
18
|
+
) + "\n";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function generateExampleInfraTs(name: string, names: { packageName: string }): string {
|
|
22
|
+
return `/**
|
|
23
|
+
* Getting-started example for the ${name} lexicon.
|
|
24
|
+
*
|
|
25
|
+
* TODO: Replace with a real infrastructure definition
|
|
26
|
+
* that uses resources from the ${name} lexicon.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
// import { SomeResource } from "${names.packageName}";
|
|
30
|
+
//
|
|
31
|
+
// export const myResource = SomeResource("example", {
|
|
32
|
+
// // properties...
|
|
33
|
+
// });
|
|
34
|
+
`;
|
|
35
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lint template generators for init-lexicon scaffold.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function generateSampleRuleTs(names: { rulePrefix: string }): string {
|
|
6
|
+
return `import type { LintRule, LintDiagnostic, LintContext } from "@intentius/chant/lint/rule";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* ${names.rulePrefix}001: Sample lint rule
|
|
10
|
+
*
|
|
11
|
+
* TODO: Replace with a real lint rule for your lexicon.
|
|
12
|
+
*/
|
|
13
|
+
export const sampleRule: LintRule = {
|
|
14
|
+
id: "${names.rulePrefix}001",
|
|
15
|
+
severity: "warning",
|
|
16
|
+
category: "style",
|
|
17
|
+
description: "Sample lint rule — replace with real checks",
|
|
18
|
+
|
|
19
|
+
check(context: LintContext): LintDiagnostic[] {
|
|
20
|
+
// TODO: Implement rule logic
|
|
21
|
+
return [];
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function generateLintRulesIndexTs(): string {
|
|
28
|
+
return `export { sampleRule } from "./sample";
|
|
29
|
+
`;
|
|
30
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LSP template generators for init-lexicon scaffold.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function generateLspCompletionsTs(name: string): string {
|
|
6
|
+
return `import type { CompletionContext, CompletionItem } from "@intentius/chant/lsp/types";
|
|
7
|
+
// import { LexiconIndex, lexiconCompletions } from "@intentius/chant/lsp/lexicon-providers";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Provide LSP completions for ${name} resources.
|
|
11
|
+
*
|
|
12
|
+
* TODO: Build a LexiconIndex from your generated lexicon data
|
|
13
|
+
* and delegate to lexiconCompletions().
|
|
14
|
+
*/
|
|
15
|
+
export function completions(ctx: CompletionContext): CompletionItem[] {
|
|
16
|
+
// const index = new LexiconIndex(lexiconData);
|
|
17
|
+
// return lexiconCompletions(ctx, index, "${name} resource");
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function generateLspHoverTs(name: string): string {
|
|
24
|
+
return `import type { HoverContext, HoverInfo } from "@intentius/chant/lsp/types";
|
|
25
|
+
// import { LexiconIndex, lexiconHover } from "@intentius/chant/lsp/lexicon-providers";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Provide LSP hover information for ${name} resources.
|
|
29
|
+
*
|
|
30
|
+
* TODO: Build a LexiconIndex from your generated lexicon data
|
|
31
|
+
* and delegate to lexiconHover().
|
|
32
|
+
*/
|
|
33
|
+
export function hover(ctx: HoverContext): HoverInfo | undefined {
|
|
34
|
+
// const index = new LexiconIndex(lexiconData);
|
|
35
|
+
// return lexiconHover(ctx, index, myCustomHoverFormatter);
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
39
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin and index template generators for init-lexicon scaffold.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export function generatePluginTs(name: string, names: { pluginVarName: string; serializerVarName: string }): string {
|
|
6
|
+
return `import type { LexiconPlugin, SkillDefinition, IntrinsicDef } from "@intentius/chant/lexicon";
|
|
7
|
+
import type { LintRule } from "@intentius/chant/lint/rule";
|
|
8
|
+
import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
|
|
9
|
+
import type { CompletionContext, CompletionItem, HoverContext, HoverInfo } from "@intentius/chant/lsp/types";
|
|
10
|
+
import type { McpToolContribution, McpResourceContribution } from "@intentius/chant/mcp/types";
|
|
11
|
+
import { ${names.serializerVarName} } from "./serializer";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* ${name} lexicon plugin.
|
|
15
|
+
*
|
|
16
|
+
* Implements all required LexiconPlugin lifecycle methods.
|
|
17
|
+
*/
|
|
18
|
+
export const ${names.pluginVarName}: LexiconPlugin = {
|
|
19
|
+
name: "${name}",
|
|
20
|
+
serializer: ${names.serializerVarName},
|
|
21
|
+
|
|
22
|
+
// ── Required lifecycle methods ────────────────────────────────
|
|
23
|
+
|
|
24
|
+
async generate(options?: { verbose?: boolean }): Promise<void> {
|
|
25
|
+
const { generate } = await import("./codegen/generate");
|
|
26
|
+
await generate(options);
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
async validate(options?: { verbose?: boolean }): Promise<void> {
|
|
30
|
+
const { validate } = await import("./validate");
|
|
31
|
+
const { printValidationResult } = await import("@intentius/chant/codegen/validate");
|
|
32
|
+
const result = await validate();
|
|
33
|
+
printValidationResult(result);
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
async coverage(options?: { verbose?: boolean; minOverall?: number }): Promise<void> {
|
|
37
|
+
// TODO: Implement coverage analysis
|
|
38
|
+
console.error("Coverage analysis not yet implemented");
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
async package(options?: { verbose?: boolean; force?: boolean }): Promise<void> {
|
|
42
|
+
const { packageLexicon } = await import("./codegen/package");
|
|
43
|
+
const { writeBundleSpec } = await import("@intentius/chant/codegen/package");
|
|
44
|
+
const { join, dirname } = await import("path");
|
|
45
|
+
const { fileURLToPath } = await import("url");
|
|
46
|
+
|
|
47
|
+
const { spec, stats } = await packageLexicon(options);
|
|
48
|
+
const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
49
|
+
writeBundleSpec(spec, join(pkgDir, "dist"));
|
|
50
|
+
|
|
51
|
+
console.error(\`Packaged \${stats.resources} resources, \${stats.ruleCount} rules, \${stats.skillCount} skills\`);
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// ── Optional extensions ────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
lintRules() {
|
|
57
|
+
const { rules } = require("./lint/rules");
|
|
58
|
+
return rules;
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
postSynthChecks() {
|
|
62
|
+
return []; // TODO: Add post-synth checks
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
skills() {
|
|
66
|
+
return []; // TODO: Add skills
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
mcpTools() {
|
|
70
|
+
return []; // TODO: Implement MCP tools
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
mcpResources() {
|
|
74
|
+
return []; // TODO: Implement MCP resources
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
detectTemplate(data: unknown) {
|
|
78
|
+
return false; // TODO: Detect if a template belongs to this lexicon
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
completionProvider(ctx: CompletionContext) {
|
|
82
|
+
const { completions } = require("./lsp/completions");
|
|
83
|
+
return completions(ctx);
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
hoverProvider(ctx: HoverContext) {
|
|
87
|
+
const { hover } = require("./lsp/hover");
|
|
88
|
+
return hover(ctx);
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
async docs(options?) {
|
|
92
|
+
const { generateDocs } = await import("./codegen/docs");
|
|
93
|
+
return generateDocs(options);
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function generateIndexTs(names: { pluginVarName: string; serializerVarName: string }): string {
|
|
100
|
+
return `// Plugin
|
|
101
|
+
export { ${names.pluginVarName} } from "./plugin";
|
|
102
|
+
|
|
103
|
+
// Serializer
|
|
104
|
+
export { ${names.serializerVarName} } from "./serializer";
|
|
105
|
+
|
|
106
|
+
// Generated resources — export everything from generated index
|
|
107
|
+
// After running \`chant generate\`, this re-exports all resource classes
|
|
108
|
+
// export * from "./generated/index";
|
|
109
|
+
`;
|
|
110
|
+
}
|