@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.
- package/README.md +365 -0
- package/package.json +22 -0
- package/src/attrref.test.ts +148 -0
- package/src/attrref.ts +50 -0
- package/src/barrel.test.ts +157 -0
- package/src/barrel.ts +101 -0
- package/src/bench.test.ts +227 -0
- package/src/build.test.ts +437 -0
- package/src/build.ts +425 -0
- package/src/builder.test.ts +312 -0
- package/src/builder.ts +56 -0
- package/src/child-project.ts +44 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/README.md +26 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/astro.config.mjs +14 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/package.json +16 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content/docs/index.mdx +8 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/src/content.config.ts +7 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/docs/tsconfig.json +10 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/examples/getting-started/.gitkeep +0 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/justfile +26 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +29 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs.ts +25 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/generate-cli.ts +8 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/generate.ts +74 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/naming.ts +33 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +25 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/rollback.ts +45 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/coverage.ts +11 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/generated/.gitkeep +0 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/import/generator.ts +10 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/import/parser.ts +10 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/index.ts +9 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/lint/rules/index.ts +1 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/lint/rules/sample.ts +18 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/lsp/completions.ts +14 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/lsp/hover.ts +14 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/plugin.ts +110 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/serializer.ts +24 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/spec/fetch.ts +21 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/spec/parse.ts +25 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/validate-cli.ts +4 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/validate.ts +24 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/tsconfig.json +10 -0
- package/src/cli/commands/__fixtures__/sample-rule.ts +11 -0
- package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +222 -0
- package/src/cli/commands/build.test.ts +149 -0
- package/src/cli/commands/build.ts +344 -0
- package/src/cli/commands/diff.test.ts +148 -0
- package/src/cli/commands/diff.ts +221 -0
- package/src/cli/commands/doctor.test.ts +239 -0
- package/src/cli/commands/doctor.ts +224 -0
- package/src/cli/commands/import.test.ts +379 -0
- package/src/cli/commands/import.ts +335 -0
- package/src/cli/commands/init-lexicon.test.ts +297 -0
- package/src/cli/commands/init-lexicon.ts +993 -0
- package/src/cli/commands/init.test.ts +317 -0
- package/src/cli/commands/init.ts +505 -0
- package/src/cli/commands/licenses.ts +165 -0
- package/src/cli/commands/lint.test.ts +332 -0
- package/src/cli/commands/lint.ts +408 -0
- package/src/cli/commands/list.test.ts +100 -0
- package/src/cli/commands/list.ts +108 -0
- package/src/cli/commands/update.test.ts +38 -0
- package/src/cli/commands/update.ts +207 -0
- package/src/cli/conflict-check.test.ts +255 -0
- package/src/cli/conflict-check.ts +89 -0
- package/src/cli/debug.ts +8 -0
- package/src/cli/format.test.ts +140 -0
- package/src/cli/format.ts +133 -0
- package/src/cli/handlers/build.ts +58 -0
- package/src/cli/handlers/dev.ts +38 -0
- package/src/cli/handlers/init.ts +46 -0
- package/src/cli/handlers/lint.ts +36 -0
- package/src/cli/handlers/misc.ts +57 -0
- package/src/cli/handlers/serve.ts +26 -0
- package/src/cli/index.ts +3 -0
- package/src/cli/lsp/capabilities.ts +46 -0
- package/src/cli/lsp/diagnostics.ts +52 -0
- package/src/cli/lsp/server.test.ts +618 -0
- package/src/cli/lsp/server.ts +393 -0
- package/src/cli/main.test.ts +257 -0
- package/src/cli/main.ts +224 -0
- package/src/cli/mcp/resources/context.ts +59 -0
- package/src/cli/mcp/server.test.ts +747 -0
- package/src/cli/mcp/server.ts +402 -0
- package/src/cli/mcp/tools/build.ts +117 -0
- package/src/cli/mcp/tools/import.ts +48 -0
- package/src/cli/mcp/tools/lint.ts +45 -0
- package/src/cli/plugins.test.ts +31 -0
- package/src/cli/plugins.ts +94 -0
- package/src/cli/registry.ts +73 -0
- package/src/cli/reporters/stylish.test.ts +282 -0
- package/src/cli/reporters/stylish.ts +186 -0
- package/src/cli/watch.test.ts +81 -0
- package/src/cli/watch.ts +101 -0
- package/src/codegen/case.test.ts +30 -0
- package/src/codegen/case.ts +11 -0
- package/src/codegen/coverage.ts +167 -0
- package/src/codegen/docs.ts +634 -0
- package/src/codegen/fetch.test.ts +119 -0
- package/src/codegen/fetch.ts +261 -0
- package/src/codegen/generate-registry.test.ts +118 -0
- package/src/codegen/generate-registry.ts +107 -0
- package/src/codegen/generate-runtime-index.test.ts +81 -0
- package/src/codegen/generate-runtime-index.ts +99 -0
- package/src/codegen/generate-typescript.test.ts +146 -0
- package/src/codegen/generate-typescript.ts +161 -0
- package/src/codegen/generate.ts +206 -0
- package/src/codegen/json-patch.test.ts +113 -0
- package/src/codegen/json-patch.ts +151 -0
- package/src/codegen/json-schema.test.ts +196 -0
- package/src/codegen/json-schema.ts +209 -0
- package/src/codegen/naming.ts +201 -0
- package/src/codegen/package.ts +161 -0
- package/src/codegen/rollback.test.ts +92 -0
- package/src/codegen/rollback.ts +115 -0
- package/src/codegen/topo-sort.test.ts +69 -0
- package/src/codegen/topo-sort.ts +46 -0
- package/src/codegen/typecheck.test.ts +37 -0
- package/src/codegen/typecheck.ts +74 -0
- package/src/codegen/validate.test.ts +86 -0
- package/src/codegen/validate.ts +143 -0
- package/src/composite.test.ts +426 -0
- package/src/composite.ts +243 -0
- package/src/config.test.ts +91 -0
- package/src/config.ts +87 -0
- package/src/declarable.test.ts +160 -0
- package/src/declarable.ts +47 -0
- package/src/detectLexicon.test.ts +236 -0
- package/src/detectLexicon.ts +37 -0
- package/src/discovery/cache.test.ts +78 -0
- package/src/discovery/cache.ts +86 -0
- package/src/discovery/collect.test.ts +269 -0
- package/src/discovery/collect.ts +51 -0
- package/src/discovery/cycles.test.ts +238 -0
- package/src/discovery/cycles.ts +107 -0
- package/src/discovery/files.test.ts +154 -0
- package/src/discovery/files.ts +61 -0
- package/src/discovery/graph.test.ts +476 -0
- package/src/discovery/graph.ts +150 -0
- package/src/discovery/import.test.ts +199 -0
- package/src/discovery/import.ts +20 -0
- package/src/discovery/index.test.ts +272 -0
- package/src/discovery/index.ts +132 -0
- package/src/discovery/resolve.test.ts +267 -0
- package/src/discovery/resolve.ts +54 -0
- package/src/errors.test.ts +138 -0
- package/src/errors.ts +86 -0
- package/src/import/base-parser.test.ts +67 -0
- package/src/import/base-parser.ts +48 -0
- package/src/import/generator.ts +21 -0
- package/src/import/ir-utils.test.ts +103 -0
- package/src/import/ir-utils.ts +87 -0
- package/src/import/parser.ts +41 -0
- package/src/index.ts +60 -0
- package/src/intrinsic-interpolation.test.ts +91 -0
- package/src/intrinsic-interpolation.ts +89 -0
- package/src/intrinsic.test.ts +69 -0
- package/src/intrinsic.ts +43 -0
- package/src/lexicon-integrity.test.ts +94 -0
- package/src/lexicon-integrity.ts +69 -0
- package/src/lexicon-manifest.test.ts +101 -0
- package/src/lexicon-manifest.ts +71 -0
- package/src/lexicon-output.test.ts +182 -0
- package/src/lexicon-output.ts +82 -0
- package/src/lexicon-schema.test.ts +239 -0
- package/src/lexicon-schema.ts +144 -0
- package/src/lexicon.ts +212 -0
- package/src/lint/config-overrides.test.ts +254 -0
- package/src/lint/config.test.ts +644 -0
- package/src/lint/config.ts +375 -0
- package/src/lint/declarative.test.ts +256 -0
- package/src/lint/declarative.ts +187 -0
- package/src/lint/engine.test.ts +465 -0
- package/src/lint/engine.ts +172 -0
- package/src/lint/named-checks.test.ts +37 -0
- package/src/lint/named-checks.ts +33 -0
- package/src/lint/parser.test.ts +129 -0
- package/src/lint/parser.ts +42 -0
- package/src/lint/post-synth.test.ts +113 -0
- package/src/lint/post-synth.ts +76 -0
- package/src/lint/presets/relaxed.json +19 -0
- package/src/lint/presets/strict.json +19 -0
- package/src/lint/rule-loader.test.ts +67 -0
- package/src/lint/rule-loader.ts +67 -0
- package/src/lint/rule-options.test.ts +141 -0
- package/src/lint/rule.test.ts +196 -0
- package/src/lint/rule.ts +98 -0
- package/src/lint/rules/barrel-import-style.test.ts +80 -0
- package/src/lint/rules/barrel-import-style.ts +59 -0
- package/src/lint/rules/composite-scope.ts +55 -0
- package/src/lint/rules/cor017-composite-name-match.test.ts +107 -0
- package/src/lint/rules/cor017-composite-name-match.ts +108 -0
- package/src/lint/rules/cor018-composite-prefer-lexicon-type.test.ts +172 -0
- package/src/lint/rules/cor018-composite-prefer-lexicon-type.ts +167 -0
- package/src/lint/rules/declarable-naming-convention.test.ts +69 -0
- package/src/lint/rules/declarable-naming-convention.ts +70 -0
- package/src/lint/rules/enforce-barrel-import.test.ts +169 -0
- package/src/lint/rules/enforce-barrel-import.ts +81 -0
- package/src/lint/rules/enforce-barrel-ref.test.ts +114 -0
- package/src/lint/rules/enforce-barrel-ref.ts +75 -0
- package/src/lint/rules/evl001-non-literal-expression.test.ts +158 -0
- package/src/lint/rules/evl001-non-literal-expression.ts +149 -0
- package/src/lint/rules/evl002-control-flow-resource.test.ts +110 -0
- package/src/lint/rules/evl002-control-flow-resource.ts +61 -0
- package/src/lint/rules/evl003-dynamic-property-access.test.ts +63 -0
- package/src/lint/rules/evl003-dynamic-property-access.ts +41 -0
- package/src/lint/rules/evl004-spread-non-const.test.ts +130 -0
- package/src/lint/rules/evl004-spread-non-const.ts +111 -0
- package/src/lint/rules/evl005-resource-block-body.test.ts +59 -0
- package/src/lint/rules/evl005-resource-block-body.ts +49 -0
- package/src/lint/rules/evl006-barrel-usage.test.ts +63 -0
- package/src/lint/rules/evl006-barrel-usage.ts +95 -0
- package/src/lint/rules/evl007-invalid-siblings.test.ts +87 -0
- package/src/lint/rules/evl007-invalid-siblings.ts +139 -0
- package/src/lint/rules/evl008-unresolvable-barrel-ref.test.ts +118 -0
- package/src/lint/rules/evl008-unresolvable-barrel-ref.ts +140 -0
- package/src/lint/rules/evl009-composite-no-constant.test.ts +162 -0
- package/src/lint/rules/evl009-composite-no-constant.ts +171 -0
- package/src/lint/rules/evl010-composite-no-transform.test.ts +121 -0
- package/src/lint/rules/evl010-composite-no-transform.ts +69 -0
- package/src/lint/rules/export-required.test.ts +213 -0
- package/src/lint/rules/export-required.ts +158 -0
- package/src/lint/rules/file-declarable-limit.test.ts +148 -0
- package/src/lint/rules/file-declarable-limit.ts +96 -0
- package/src/lint/rules/flat-declarations.test.ts +210 -0
- package/src/lint/rules/flat-declarations.ts +70 -0
- package/src/lint/rules/index.ts +99 -0
- package/src/lint/rules/no-cyclic-declarable-ref.test.ts +135 -0
- package/src/lint/rules/no-cyclic-declarable-ref.ts +178 -0
- package/src/lint/rules/no-redundant-type-import.test.ts +129 -0
- package/src/lint/rules/no-redundant-type-import.ts +85 -0
- package/src/lint/rules/no-redundant-value-cast.test.ts +51 -0
- package/src/lint/rules/no-redundant-value-cast.ts +46 -0
- package/src/lint/rules/no-string-ref.test.ts +100 -0
- package/src/lint/rules/no-string-ref.ts +66 -0
- package/src/lint/rules/no-unused-declarable-import.test.ts +74 -0
- package/src/lint/rules/no-unused-declarable-import.ts +103 -0
- package/src/lint/rules/no-unused-declarable.test.ts +134 -0
- package/src/lint/rules/no-unused-declarable.ts +118 -0
- package/src/lint/rules/prefer-namespace-import.test.ts +102 -0
- package/src/lint/rules/prefer-namespace-import.ts +63 -0
- package/src/lint/rules/single-concern-file.test.ts +156 -0
- package/src/lint/rules/single-concern-file.ts +98 -0
- package/src/lint/rules/stale-barrel-types.ts +60 -0
- package/src/lint/selectors.test.ts +113 -0
- package/src/lint/selectors.ts +188 -0
- package/src/lsp/lexicon-providers.ts +191 -0
- package/src/lsp/types.ts +79 -0
- package/src/mcp/types.ts +22 -0
- package/src/project/scan.test.ts +178 -0
- package/src/project/scan.ts +182 -0
- package/src/project/sync.test.ts +87 -0
- package/src/project/sync.ts +46 -0
- package/src/project-validation.test.ts +64 -0
- package/src/project-validation.ts +79 -0
- package/src/pseudo-parameter.test.ts +39 -0
- package/src/pseudo-parameter.ts +47 -0
- package/src/runtime.ts +68 -0
- package/src/serializer-walker.test.ts +124 -0
- package/src/serializer-walker.ts +83 -0
- package/src/serializer.ts +42 -0
- package/src/sort.test.ts +290 -0
- package/src/sort.ts +58 -0
- package/src/stack-output.ts +82 -0
- package/src/types.test.ts +307 -0
- package/src/types.ts +46 -0
- package/src/utils.test.ts +195 -0
- package/src/utils.ts +46 -0
- package/src/validation.test.ts +308 -0
- package/src/validation.ts +50 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { describe, test, expect } from "bun:test";
|
|
2
|
+
import { Builder } from "./builder";
|
|
3
|
+
import type { Declarable } from "./declarable";
|
|
4
|
+
import { DECLARABLE_MARKER } from "./declarable";
|
|
5
|
+
|
|
6
|
+
// Test implementation of Declarable for testing
|
|
7
|
+
interface TestResource extends Declarable {
|
|
8
|
+
name: string;
|
|
9
|
+
type: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Simple builder implementation
|
|
14
|
+
class SimpleResourceBuilder extends Builder<TestResource> {
|
|
15
|
+
private name?: string;
|
|
16
|
+
private type?: string;
|
|
17
|
+
private description?: string;
|
|
18
|
+
|
|
19
|
+
withName(name: string): this {
|
|
20
|
+
this.name = name;
|
|
21
|
+
return this;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
withType(type: string): this {
|
|
25
|
+
this.type = type;
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
withDescription(description: string): this {
|
|
30
|
+
this.description = description;
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
build(): TestResource {
|
|
35
|
+
if (!this.name || !this.type) {
|
|
36
|
+
throw new Error("Name and type are required");
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
entityType: "TestResource",
|
|
40
|
+
[DECLARABLE_MARKER]: true,
|
|
41
|
+
name: this.name,
|
|
42
|
+
type: this.type,
|
|
43
|
+
description: this.description,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Complex builder with validation
|
|
49
|
+
class ValidatedResourceBuilder extends Builder<TestResource> {
|
|
50
|
+
private name?: string;
|
|
51
|
+
private type?: string;
|
|
52
|
+
|
|
53
|
+
withName(name: string): this {
|
|
54
|
+
if (!name || name.trim() === "") {
|
|
55
|
+
throw new Error("Name cannot be empty");
|
|
56
|
+
}
|
|
57
|
+
this.name = name;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
withType(type: string): this {
|
|
62
|
+
const validTypes = ["A", "B", "C"];
|
|
63
|
+
if (!validTypes.includes(type)) {
|
|
64
|
+
throw new Error(`Type must be one of: ${validTypes.join(", ")}`);
|
|
65
|
+
}
|
|
66
|
+
this.type = type;
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
build(): TestResource {
|
|
71
|
+
if (!this.name || !this.type) {
|
|
72
|
+
throw new Error("Name and type are required");
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
entityType: "TestResource",
|
|
76
|
+
[DECLARABLE_MARKER]: true,
|
|
77
|
+
name: this.name,
|
|
78
|
+
type: this.type,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Builder with default values
|
|
84
|
+
class DefaultsResourceBuilder extends Builder<TestResource> {
|
|
85
|
+
private name = "default-name";
|
|
86
|
+
private type = "default-type";
|
|
87
|
+
private description = "default-description";
|
|
88
|
+
|
|
89
|
+
withName(name: string): this {
|
|
90
|
+
this.name = name;
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
withType(type: string): this {
|
|
95
|
+
this.type = type;
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
withDescription(description: string): this {
|
|
100
|
+
this.description = description;
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
build(): TestResource {
|
|
105
|
+
return {
|
|
106
|
+
entityType: "TestResource",
|
|
107
|
+
[DECLARABLE_MARKER]: true,
|
|
108
|
+
name: this.name,
|
|
109
|
+
type: this.type,
|
|
110
|
+
description: this.description,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
describe("Builder", () => {
|
|
116
|
+
describe("fluent API", () => {
|
|
117
|
+
test("allows chaining multiple method calls", () => {
|
|
118
|
+
const builder = new SimpleResourceBuilder()
|
|
119
|
+
.withName("test-resource")
|
|
120
|
+
.withType("test-type")
|
|
121
|
+
.withDescription("test-description");
|
|
122
|
+
|
|
123
|
+
const resource = builder.build();
|
|
124
|
+
expect(resource.name).toBe("test-resource");
|
|
125
|
+
expect(resource.type).toBe("test-type");
|
|
126
|
+
expect(resource.description).toBe("test-description");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("returns 'this' for chaining", () => {
|
|
130
|
+
const builder = new SimpleResourceBuilder();
|
|
131
|
+
const result1 = builder.withName("test");
|
|
132
|
+
const result2 = result1.withType("type");
|
|
133
|
+
|
|
134
|
+
expect(result1).toBe(builder);
|
|
135
|
+
expect(result2).toBe(builder);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("allows arbitrary method call order", () => {
|
|
139
|
+
const resource1 = new SimpleResourceBuilder()
|
|
140
|
+
.withName("test")
|
|
141
|
+
.withType("type")
|
|
142
|
+
.build();
|
|
143
|
+
|
|
144
|
+
const resource2 = new SimpleResourceBuilder()
|
|
145
|
+
.withType("type")
|
|
146
|
+
.withName("test")
|
|
147
|
+
.build();
|
|
148
|
+
|
|
149
|
+
expect(resource1.name).toBe(resource2.name);
|
|
150
|
+
expect(resource1.type).toBe(resource2.type);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe("build method", () => {
|
|
155
|
+
test("returns a valid Declarable entity", () => {
|
|
156
|
+
const resource = new SimpleResourceBuilder()
|
|
157
|
+
.withName("test")
|
|
158
|
+
.withType("type")
|
|
159
|
+
.build();
|
|
160
|
+
|
|
161
|
+
expect(resource.entityType).toBe("TestResource");
|
|
162
|
+
expect(resource[DECLARABLE_MARKER]).toBe(true);
|
|
163
|
+
expect(resource.name).toBe("test");
|
|
164
|
+
expect(resource.type).toBe("type");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test("throws when required properties are missing", () => {
|
|
168
|
+
const builder = new SimpleResourceBuilder().withName("test");
|
|
169
|
+
|
|
170
|
+
expect(() => builder.build()).toThrow("Name and type are required");
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("includes optional properties when set", () => {
|
|
174
|
+
const resource = new SimpleResourceBuilder()
|
|
175
|
+
.withName("test")
|
|
176
|
+
.withType("type")
|
|
177
|
+
.withDescription("A test resource")
|
|
178
|
+
.build();
|
|
179
|
+
|
|
180
|
+
expect(resource.description).toBe("A test resource");
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
test("omits optional properties when not set", () => {
|
|
184
|
+
const resource = new SimpleResourceBuilder()
|
|
185
|
+
.withName("test")
|
|
186
|
+
.withType("type")
|
|
187
|
+
.build();
|
|
188
|
+
|
|
189
|
+
expect(resource.description).toBeUndefined();
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe("extension patterns", () => {
|
|
194
|
+
test("supports custom validation in setter methods", () => {
|
|
195
|
+
const builder = new ValidatedResourceBuilder();
|
|
196
|
+
|
|
197
|
+
expect(() => builder.withName("")).toThrow("Name cannot be empty");
|
|
198
|
+
expect(() => builder.withName(" ")).toThrow("Name cannot be empty");
|
|
199
|
+
expect(() => builder.withType("Invalid")).toThrow(
|
|
200
|
+
"Type must be one of: A, B, C"
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("allows valid values through validation", () => {
|
|
205
|
+
const resource = new ValidatedResourceBuilder()
|
|
206
|
+
.withName("valid-name")
|
|
207
|
+
.withType("A")
|
|
208
|
+
.build();
|
|
209
|
+
|
|
210
|
+
expect(resource.name).toBe("valid-name");
|
|
211
|
+
expect(resource.type).toBe("A");
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test("supports builders with default values", () => {
|
|
215
|
+
const resource = new DefaultsResourceBuilder().build();
|
|
216
|
+
|
|
217
|
+
expect(resource.name).toBe("default-name");
|
|
218
|
+
expect(resource.type).toBe("default-type");
|
|
219
|
+
expect(resource.description).toBe("default-description");
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("allows overriding default values", () => {
|
|
223
|
+
const resource = new DefaultsResourceBuilder()
|
|
224
|
+
.withName("custom-name")
|
|
225
|
+
.build();
|
|
226
|
+
|
|
227
|
+
expect(resource.name).toBe("custom-name");
|
|
228
|
+
expect(resource.type).toBe("default-type");
|
|
229
|
+
expect(resource.description).toBe("default-description");
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
describe("reusability", () => {
|
|
234
|
+
test("builder can be reused to create multiple instances", () => {
|
|
235
|
+
const builder = new DefaultsResourceBuilder();
|
|
236
|
+
|
|
237
|
+
const resource1 = builder.build();
|
|
238
|
+
const resource2 = builder.build();
|
|
239
|
+
|
|
240
|
+
// Should create separate instances
|
|
241
|
+
expect(resource1).not.toBe(resource2);
|
|
242
|
+
// But with same values
|
|
243
|
+
expect(resource1.name).toBe(resource2.name);
|
|
244
|
+
expect(resource1.type).toBe(resource2.type);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
test("modifying builder after build affects next build", () => {
|
|
248
|
+
const builder = new SimpleResourceBuilder()
|
|
249
|
+
.withName("initial")
|
|
250
|
+
.withType("type");
|
|
251
|
+
|
|
252
|
+
const resource1 = builder.build();
|
|
253
|
+
expect(resource1.name).toBe("initial");
|
|
254
|
+
|
|
255
|
+
builder.withName("modified");
|
|
256
|
+
const resource2 = builder.build();
|
|
257
|
+
expect(resource2.name).toBe("modified");
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
describe("type safety", () => {
|
|
262
|
+
test("build method returns correct type", () => {
|
|
263
|
+
const builder = new SimpleResourceBuilder()
|
|
264
|
+
.withName("test")
|
|
265
|
+
.withType("type");
|
|
266
|
+
|
|
267
|
+
const resource = builder.build();
|
|
268
|
+
|
|
269
|
+
// TypeScript should recognize this as TestResource
|
|
270
|
+
expect(resource.entityType).toBe("TestResource");
|
|
271
|
+
expect(resource.name).toBe("test");
|
|
272
|
+
expect(resource.type).toBe("type");
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test("fluent methods maintain builder type", () => {
|
|
276
|
+
const builder = new SimpleResourceBuilder();
|
|
277
|
+
|
|
278
|
+
// Each method should return the same builder type
|
|
279
|
+
const step1 = builder.withName("test");
|
|
280
|
+
const step2 = step1.withType("type");
|
|
281
|
+
const step3 = step2.withDescription("desc");
|
|
282
|
+
|
|
283
|
+
expect(step1).toBeInstanceOf(SimpleResourceBuilder);
|
|
284
|
+
expect(step2).toBeInstanceOf(SimpleResourceBuilder);
|
|
285
|
+
expect(step3).toBeInstanceOf(SimpleResourceBuilder);
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
describe("error handling", () => {
|
|
290
|
+
test("preserves validation errors", () => {
|
|
291
|
+
const builder = new ValidatedResourceBuilder();
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
builder.withType("Invalid");
|
|
295
|
+
} catch (error) {
|
|
296
|
+
expect(error).toBeInstanceOf(Error);
|
|
297
|
+
expect((error as Error).message).toBe("Type must be one of: A, B, C");
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
test("preserves build errors", () => {
|
|
302
|
+
const builder = new SimpleResourceBuilder();
|
|
303
|
+
|
|
304
|
+
try {
|
|
305
|
+
builder.build();
|
|
306
|
+
} catch (error) {
|
|
307
|
+
expect(error).toBeInstanceOf(Error);
|
|
308
|
+
expect((error as Error).message).toBe("Name and type are required");
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
});
|
package/src/builder.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Declarable } from "./declarable";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base class for builder pattern implementations
|
|
5
|
+
*
|
|
6
|
+
* Provides a fluent API for constructing Declarable entities.
|
|
7
|
+
* Subclasses should implement the build() method to return
|
|
8
|
+
* a fully constructed Declarable entity.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* class ResourceBuilder extends Builder<MyResource> {
|
|
13
|
+
* private name?: string;
|
|
14
|
+
* private type?: string;
|
|
15
|
+
*
|
|
16
|
+
* withName(name: string): this {
|
|
17
|
+
* this.name = name;
|
|
18
|
+
* return this;
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* withType(type: string): this {
|
|
22
|
+
* this.type = type;
|
|
23
|
+
* return this;
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* build(): MyResource {
|
|
27
|
+
* if (!this.name || !this.type) {
|
|
28
|
+
* throw new Error("Name and type are required");
|
|
29
|
+
* }
|
|
30
|
+
* return {
|
|
31
|
+
* entityType: "MyResource",
|
|
32
|
+
* [DECLARABLE_MARKER]: true,
|
|
33
|
+
* name: this.name,
|
|
34
|
+
* type: this.type,
|
|
35
|
+
* };
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
* const resource = new ResourceBuilder()
|
|
40
|
+
* .withName("myResource")
|
|
41
|
+
* .withType("custom")
|
|
42
|
+
* .build();
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export abstract class Builder<T extends Declarable> {
|
|
46
|
+
/**
|
|
47
|
+
* Builds and returns the final Declarable entity
|
|
48
|
+
*
|
|
49
|
+
* Subclasses must implement this method to construct
|
|
50
|
+
* and return the entity with all configured properties.
|
|
51
|
+
*
|
|
52
|
+
* @returns The constructed Declarable entity
|
|
53
|
+
* @throws Error if required properties are not set
|
|
54
|
+
*/
|
|
55
|
+
abstract build(): T;
|
|
56
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Child Project — represents a nested project directory that gets built
|
|
3
|
+
* independently and referenced from a parent as a single deployment unit.
|
|
4
|
+
*
|
|
5
|
+
* Lexicons create ChildProjectInstance via their own factory (e.g. `nestedStack()`).
|
|
6
|
+
* The core build pipeline detects these and recursively builds children.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { DECLARABLE_MARKER, type Declarable } from "./declarable";
|
|
10
|
+
import type { BuildResult } from "./build";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Marker symbol for child project identification.
|
|
14
|
+
*/
|
|
15
|
+
export const CHILD_PROJECT_MARKER = Symbol.for("chant.childProject");
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A child project instance — a Declarable representing a separately-built
|
|
19
|
+
* project directory referenced from a parent.
|
|
20
|
+
*/
|
|
21
|
+
export interface ChildProjectInstance extends Declarable {
|
|
22
|
+
readonly [CHILD_PROJECT_MARKER]: true;
|
|
23
|
+
readonly [DECLARABLE_MARKER]: true;
|
|
24
|
+
readonly lexicon: string;
|
|
25
|
+
readonly entityType: string;
|
|
26
|
+
readonly kind: "resource";
|
|
27
|
+
readonly projectPath: string;
|
|
28
|
+
readonly logicalName: string;
|
|
29
|
+
readonly outputs: Record<string, unknown>;
|
|
30
|
+
readonly options: Record<string, unknown>;
|
|
31
|
+
buildResult?: BuildResult;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Type guard for ChildProjectInstance.
|
|
36
|
+
*/
|
|
37
|
+
export function isChildProject(value: unknown): value is ChildProjectInstance {
|
|
38
|
+
return (
|
|
39
|
+
typeof value === "object" &&
|
|
40
|
+
value !== null &&
|
|
41
|
+
CHILD_PROJECT_MARKER in value &&
|
|
42
|
+
(value as Record<symbol, unknown>)[CHILD_PROJECT_MARKER] === true
|
|
43
|
+
);
|
|
44
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# @intentius/chant-lexicon-fixture
|
|
2
|
+
|
|
3
|
+
fixture lexicon plugin for [chant](https://github.com/intentius/chant).
|
|
4
|
+
|
|
5
|
+
## Getting started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Generate types from upstream spec
|
|
9
|
+
just generate
|
|
10
|
+
|
|
11
|
+
# Validate generated artifacts
|
|
12
|
+
just validate
|
|
13
|
+
|
|
14
|
+
# Generate documentation
|
|
15
|
+
just docs
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Project structure
|
|
19
|
+
|
|
20
|
+
- `src/plugin.ts` — LexiconPlugin with all lifecycle methods
|
|
21
|
+
- `src/serializer.ts` — Build output serializer
|
|
22
|
+
- `src/codegen/` — Code generation pipeline
|
|
23
|
+
- `src/spec/` — Upstream schema fetching and parsing
|
|
24
|
+
- `src/lint/rules/` — Lint rules
|
|
25
|
+
- `src/lsp/` — LSP completions and hover
|
|
26
|
+
- `src/generated/` — Generated artifacts (do not edit)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { defineConfig } from 'astro/config';
|
|
3
|
+
import starlight from '@astrojs/starlight';
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
integrations: [
|
|
7
|
+
starlight({
|
|
8
|
+
title: 'Fixture',
|
|
9
|
+
sidebar: [
|
|
10
|
+
{ label: 'Overview', slug: '' },
|
|
11
|
+
],
|
|
12
|
+
}),
|
|
13
|
+
],
|
|
14
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@intentius/chant-lexicon-fixture-docs",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"private": true,
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "astro dev",
|
|
8
|
+
"build": "astro build",
|
|
9
|
+
"preview": "astro preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@astrojs/starlight": "^0.37.6",
|
|
13
|
+
"astro": "^5.6.1",
|
|
14
|
+
"sharp": "^0.34.2"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { defineCollection } from 'astro:content';
|
|
2
|
+
import { docsLoader } from '@astrojs/starlight/loaders';
|
|
3
|
+
import { docsSchema } from '@astrojs/starlight/schema';
|
|
4
|
+
|
|
5
|
+
export const collections = {
|
|
6
|
+
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
|
|
7
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Default recipe - list all available commands
|
|
2
|
+
default:
|
|
3
|
+
@just --list
|
|
4
|
+
|
|
5
|
+
# Generate types and metadata from upstream schemas
|
|
6
|
+
generate:
|
|
7
|
+
bun run src/codegen/generate-cli.ts
|
|
8
|
+
|
|
9
|
+
# Validate generated artifacts
|
|
10
|
+
validate:
|
|
11
|
+
bun run src/validate-cli.ts
|
|
12
|
+
|
|
13
|
+
# Generate docs site, install deps, and start dev server
|
|
14
|
+
docs:
|
|
15
|
+
bun run src/codegen/docs-cli.ts
|
|
16
|
+
bun install --cwd docs
|
|
17
|
+
bun --cwd docs dev
|
|
18
|
+
|
|
19
|
+
# Build docs site for production
|
|
20
|
+
docs-build:
|
|
21
|
+
bun run src/codegen/docs-cli.ts
|
|
22
|
+
bun install --cwd docs
|
|
23
|
+
bun --cwd docs build
|
|
24
|
+
|
|
25
|
+
# Package the lexicon (generate + validate)
|
|
26
|
+
package: generate validate
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@intentius/chant-lexicon-fixture",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"private": true,
|
|
6
|
+
"files": [
|
|
7
|
+
"src/",
|
|
8
|
+
"dist/"
|
|
9
|
+
],
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./src/index.ts",
|
|
12
|
+
"./*": "./src/*",
|
|
13
|
+
"./manifest": "./dist/manifest.json",
|
|
14
|
+
"./meta": "./dist/meta.json",
|
|
15
|
+
"./types": "./dist/types/index.d.ts"
|
|
16
|
+
},
|
|
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"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@intentius/chant": "workspace:*"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"typescript": "^5.9.3"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { docsPipeline, writeDocsSite } from "@intentius/chant/codegen/docs";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate documentation site for the fixture lexicon.
|
|
5
|
+
*/
|
|
6
|
+
export async function generateDocs(options?: { verbose?: boolean }): Promise<void> {
|
|
7
|
+
const config = {
|
|
8
|
+
name: "fixture",
|
|
9
|
+
displayName: "Fixture",
|
|
10
|
+
description: "fixture lexicon documentation",
|
|
11
|
+
distDir: "./dist",
|
|
12
|
+
outDir: "./docs",
|
|
13
|
+
// TODO: Implement service grouping for your provider
|
|
14
|
+
serviceFromType: (type: string) => type.split("::")[1] ?? type,
|
|
15
|
+
// TODO: Implement resource documentation URLs
|
|
16
|
+
resourceTypeUrl: (type: string) => `#${type}`,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const result = docsPipeline(config);
|
|
20
|
+
writeDocsSite(config, result);
|
|
21
|
+
|
|
22
|
+
if (options?.verbose) {
|
|
23
|
+
console.error("Documentation generated");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { generate, writeGeneratedFiles } from "./generate";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
|
|
6
|
+
const pkgDir = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
7
|
+
const result = await generate({ verbose: true });
|
|
8
|
+
writeGeneratedFiles(result, pkgDir);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { generatePipeline, writeGeneratedArtifacts } from "@intentius/chant/codegen/generate";
|
|
2
|
+
import type { GenerateResult } from "@intentius/chant/codegen/generate";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Run the code generation pipeline.
|
|
8
|
+
*
|
|
9
|
+
* Each callback has a TODO describing what to implement.
|
|
10
|
+
*/
|
|
11
|
+
export async function generate(options?: { verbose?: boolean }): Promise<GenerateResult> {
|
|
12
|
+
const result = await generatePipeline({
|
|
13
|
+
// Must return Map<typeName, Buffer> — each entry is one schema file.
|
|
14
|
+
// Example: fetch a zip, extract JSON files, key by type name.
|
|
15
|
+
// See lexicons/aws/src/spec/fetch.ts for a working example.
|
|
16
|
+
fetchSchemas: async (opts) => {
|
|
17
|
+
throw new Error("TODO: implement fetchSchemas — download your upstream spec");
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
// Must return a ParsedResult (with propertyTypes[] and enums[] at minimum).
|
|
21
|
+
// Return null to skip a schema file.
|
|
22
|
+
// See lexicons/aws/src/spec/parse.ts for a working example.
|
|
23
|
+
parseSchema: (name, data) => {
|
|
24
|
+
throw new Error("TODO: implement parseSchema — parse a single schema file");
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// Must return a NamingStrategy instance.
|
|
28
|
+
// See lexicons/aws/src/codegen/naming.ts and ./naming.ts for setup.
|
|
29
|
+
createNaming: (results) => {
|
|
30
|
+
throw new Error("TODO: implement createNaming — return a NamingStrategy instance");
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
// Must return a string of JSON (the lexicon registry).
|
|
34
|
+
// Use buildRegistry + serializeRegistry from @intentius/chant/codegen/generate-registry.
|
|
35
|
+
// See lexicons/aws/src/codegen/generate.ts for a working example.
|
|
36
|
+
generateRegistry: (results, naming) => {
|
|
37
|
+
throw new Error("TODO: implement generateRegistry — produce lexicon JSON");
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
// Must return a string of TypeScript declarations (.d.ts content).
|
|
41
|
+
// See lexicons/aws/src/codegen/generate.ts for a working example.
|
|
42
|
+
generateTypes: (results, naming) => {
|
|
43
|
+
throw new Error("TODO: implement generateTypes — produce .d.ts content");
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
// Must return a string of TypeScript (runtime index with factory exports).
|
|
47
|
+
// Use generateRuntimeIndex from @intentius/chant/codegen/generate-runtime-index.
|
|
48
|
+
// See lexicons/aws/src/codegen/generate.ts for a working example.
|
|
49
|
+
generateRuntimeIndex: (results, naming) => {
|
|
50
|
+
throw new Error("TODO: implement generateRuntimeIndex — produce index.ts content");
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (options?.verbose) {
|
|
55
|
+
console.error(`Generated ${result.resources} resources, ${result.properties} property types`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Write generated files to the package directory.
|
|
63
|
+
*/
|
|
64
|
+
export function writeGeneratedFiles(result: GenerateResult, pkgDir?: string): void {
|
|
65
|
+
const dir = pkgDir ?? dirname(dirname(fileURLToPath(import.meta.url)));
|
|
66
|
+
writeGeneratedArtifacts({
|
|
67
|
+
baseDir: dir,
|
|
68
|
+
files: {
|
|
69
|
+
"lexicon.json": result.lexiconJSON,
|
|
70
|
+
"index.d.ts": result.typesDTS,
|
|
71
|
+
"index.ts": result.indexTS,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
}
|