@fabricorg/fabric-gen 0.3.1 → 0.4.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/CHANGELOG.md +59 -0
- package/README.md +36 -1
- package/dist/chunk-CUNWMAA2.js +251 -0
- package/dist/chunk-CUNWMAA2.js.map +1 -0
- package/dist/cli.cjs +171 -15
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +7 -17
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +179 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -1
- package/dist/index.d.ts +34 -1
- package/dist/index.js +13 -3
- package/package.json +14 -12
- package/dist/chunk-QOD7G4YK.js +0 -74
- package/dist/chunk-QOD7G4YK.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,64 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- Updated dependencies [89982ba]
|
|
9
|
+
- Updated dependencies [6f5471b]
|
|
10
|
+
- Updated dependencies [89982ba]
|
|
11
|
+
- Updated dependencies [89982ba]
|
|
12
|
+
- @fabricorg/compiler@2.2.0
|
|
13
|
+
- @fabricorg/gen-capability@0.5.0
|
|
14
|
+
- @fabricorg/gen-conformance@0.3.0
|
|
15
|
+
- @fabricorg/gen-graphql@3.1.0
|
|
16
|
+
- @fabricorg/sdui-release@0.3.0
|
|
17
|
+
- @fabricorg/assembly@0.3.0
|
|
18
|
+
|
|
19
|
+
## 0.4.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- bd67ad6: Add non-destructive capability initialization and fail-closed application
|
|
24
|
+
composition checks for approved lockfiles, exact runtime artifacts, and
|
|
25
|
+
promoted experience releases.
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- Updated dependencies [62dd1ca]
|
|
30
|
+
- Updated dependencies [4e585a4]
|
|
31
|
+
- Updated dependencies [b932767]
|
|
32
|
+
- Updated dependencies [1ba3a9e]
|
|
33
|
+
- Updated dependencies [8e9a571]
|
|
34
|
+
- Updated dependencies [e6aede7]
|
|
35
|
+
- @fabricorg/assembly@0.2.0
|
|
36
|
+
- @fabricorg/gen-capability@0.4.1
|
|
37
|
+
- @fabricorg/sdui-release@0.2.0
|
|
38
|
+
- @fabricorg/compiler@2.1.1
|
|
39
|
+
- @fabricorg/gen-conformance@0.2.1
|
|
40
|
+
- @fabricorg/gen-graphql@3.0.1
|
|
41
|
+
- @fabricorg/gen-sdui@0.5.1
|
|
42
|
+
|
|
43
|
+
### Additional release notes
|
|
44
|
+
|
|
45
|
+
### Minor Changes
|
|
46
|
+
|
|
47
|
+
- Add `init capability` for non-destructive compiler-valid scaffolding and
|
|
48
|
+
`check-application` for exact runtime capability, assembly lockfile, and
|
|
49
|
+
promoted experience release verification.
|
|
50
|
+
|
|
51
|
+
## 0.3.2
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- Updated dependencies [c504d0a]
|
|
56
|
+
- Updated dependencies [c504d0a]
|
|
57
|
+
- @fabricorg/compiler@2.1.0
|
|
58
|
+
- @fabricorg/gen-graphql@3.0.0
|
|
59
|
+
- @fabricorg/gen-conformance@0.2.0
|
|
60
|
+
- @fabricorg/gen-capability@0.4.0
|
|
61
|
+
|
|
3
62
|
## 0.3.1
|
|
4
63
|
|
|
5
64
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# `fabric-gen`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Scaffold capability source, run independently versioned generators, and verify
|
|
4
|
+
an application composition before deployment.
|
|
5
|
+
|
|
6
|
+
Create a compiler-valid capability without copying a repository template:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
fabric-gen init capability case-review
|
|
10
|
+
fabric-gen init capability case-review --directory packages/case-review
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Initialization refuses to overwrite either `README.md` or
|
|
14
|
+
`fabric.manifest.json`.
|
|
4
15
|
|
|
5
16
|
```bash
|
|
6
17
|
fabric-gen --input fabric-manifest.json --out generated
|
|
@@ -9,3 +20,27 @@ fabric-gen --input fabric-manifest.json --out generated --check
|
|
|
9
20
|
|
|
10
21
|
`--check` performs no writes and fails for changed or stale artifacts. Generated files contain a
|
|
11
22
|
manifest digest and generator version, never timestamps.
|
|
23
|
+
|
|
24
|
+
Check the exact artifacts an application will load:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
fabric-gen check-application --config fabric.application.json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`fabric.application.json` uses paths relative to itself:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"formatVersion": 1,
|
|
35
|
+
"assembly": "./fabric.assembly.lock.json",
|
|
36
|
+
"runtimeCapabilities": "./fabric.runtime.json",
|
|
37
|
+
"releases": ["./releases/web.json"]
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The runtime file is an array of `{ "namespace", "version", "manifestDigest" }`
|
|
42
|
+
objects derived from the modules actually registered by the application. The
|
|
43
|
+
check verifies lockfile integrity, rejects missing, extra, duplicate, or
|
|
44
|
+
mismatched runtime capabilities, verifies each promoted experience release,
|
|
45
|
+
and requires every release to name the same assembly digest. It does not
|
|
46
|
+
inspect caller assertions in place of runtime artifact metadata.
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
// index.ts
|
|
2
|
+
import { access, mkdir, readFile, readdir, rm, writeFile } from "fs/promises";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { compileManifestBundle, runGenerator } from "@fabricorg/compiler";
|
|
5
|
+
import { capabilityGenerator } from "@fabricorg/gen-capability";
|
|
6
|
+
import { docsGenerator } from "@fabricorg/gen-docs";
|
|
7
|
+
import { eventsGenerator } from "@fabricorg/gen-events";
|
|
8
|
+
import { typesGenerator } from "@fabricorg/gen-types";
|
|
9
|
+
import { prismaGenerator } from "@fabricorg/gen-prisma";
|
|
10
|
+
import { graphqlGenerator } from "@fabricorg/gen-graphql";
|
|
11
|
+
import { sduiGenerator } from "@fabricorg/gen-sdui";
|
|
12
|
+
import { conformanceGenerator } from "@fabricorg/gen-conformance";
|
|
13
|
+
import {
|
|
14
|
+
assertAssemblyLockfile,
|
|
15
|
+
assertAssemblyRuntimeCompatible
|
|
16
|
+
} from "@fabricorg/assembly";
|
|
17
|
+
import {
|
|
18
|
+
assertSduiReleaseIntegrity
|
|
19
|
+
} from "@fabricorg/sdui-release";
|
|
20
|
+
var GENERATOR_TARGETS = {
|
|
21
|
+
types: typesGenerator,
|
|
22
|
+
events: eventsGenerator,
|
|
23
|
+
capability: capabilityGenerator,
|
|
24
|
+
docs: docsGenerator,
|
|
25
|
+
prisma: prismaGenerator,
|
|
26
|
+
graphql: graphqlGenerator,
|
|
27
|
+
sdui: sduiGenerator,
|
|
28
|
+
conformance: conformanceGenerator
|
|
29
|
+
};
|
|
30
|
+
var compareCanonicalStrings = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
31
|
+
var usage = [
|
|
32
|
+
"Usage:",
|
|
33
|
+
" fabric-gen init capability <namespace> [--directory <path>]",
|
|
34
|
+
" fabric-gen check-application [--config <path>]",
|
|
35
|
+
" fabric-gen --input <manifest.json> --out <directory> [--targets <list>] [--check]"
|
|
36
|
+
].join("\n");
|
|
37
|
+
var FabricGenUsageError = class extends Error {
|
|
38
|
+
name = "FabricGenUsageError";
|
|
39
|
+
};
|
|
40
|
+
function fabricGenCliExitCode(error) {
|
|
41
|
+
return error instanceof FabricGenUsageError ? 2 : 1;
|
|
42
|
+
}
|
|
43
|
+
function flagValue(args, flag) {
|
|
44
|
+
const index = args.indexOf(flag);
|
|
45
|
+
if (index < 0) return void 0;
|
|
46
|
+
const value = args[index + 1];
|
|
47
|
+
if (!value || value.startsWith("--")) throw new FabricGenUsageError(usage);
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
async function runFabricGenCommand(args) {
|
|
51
|
+
if (args[0] === "init") {
|
|
52
|
+
if (args[1] !== "capability" || !args[2] || args[2].startsWith("--")) {
|
|
53
|
+
throw new FabricGenUsageError(usage);
|
|
54
|
+
}
|
|
55
|
+
const namespace = args[2];
|
|
56
|
+
const directory = flagValue(args, "--directory") ?? namespace;
|
|
57
|
+
const result2 = await initializeCapability({ directory, namespace });
|
|
58
|
+
return `Initialized capability "${namespace}" with ${result2.created.length} files.`;
|
|
59
|
+
}
|
|
60
|
+
if (args[0] === "check-application") {
|
|
61
|
+
const configPath = flagValue(args, "--config") ?? "fabric.application.json";
|
|
62
|
+
const result2 = await checkApplication({ configPath });
|
|
63
|
+
return `Checked "${result2.application}": ${result2.capabilities} capabilities, ${result2.releases} releases.`;
|
|
64
|
+
}
|
|
65
|
+
const inputPath = flagValue(args, "--input");
|
|
66
|
+
const outputDirectory = flagValue(args, "--out");
|
|
67
|
+
if (!inputPath || !outputDirectory) throw new FabricGenUsageError(usage);
|
|
68
|
+
const result = await generateFromManifest({
|
|
69
|
+
inputPath,
|
|
70
|
+
outputDirectory,
|
|
71
|
+
targets: (flagValue(args, "--targets") ?? "types,events,capability,docs").split(",").filter(Boolean),
|
|
72
|
+
check: args.includes("--check")
|
|
73
|
+
});
|
|
74
|
+
return `${args.includes("--check") ? "Checked" : "Generated"} ${result.files.length} files.`;
|
|
75
|
+
}
|
|
76
|
+
async function readJson(file) {
|
|
77
|
+
return JSON.parse(await readFile(file, "utf8"));
|
|
78
|
+
}
|
|
79
|
+
function assertApplicationCheckConfig(value) {
|
|
80
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
81
|
+
throw new Error("Application check configuration must be a JSON object.");
|
|
82
|
+
}
|
|
83
|
+
const config = value;
|
|
84
|
+
if (config.formatVersion !== 1) throw new Error("Application check configuration formatVersion must be 1.");
|
|
85
|
+
if (typeof config.assembly !== "string" || !config.assembly) {
|
|
86
|
+
throw new Error("Application check configuration assembly must be a file path.");
|
|
87
|
+
}
|
|
88
|
+
if (typeof config.runtimeCapabilities !== "string" || !config.runtimeCapabilities) {
|
|
89
|
+
throw new Error("Application check configuration runtimeCapabilities must be a file path.");
|
|
90
|
+
}
|
|
91
|
+
if (!Array.isArray(config.releases) || !config.releases.every((entry) => typeof entry === "string" && entry)) {
|
|
92
|
+
throw new Error("Application check configuration releases must be an array of file paths.");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function checkApplication(options) {
|
|
96
|
+
const configValue = await readJson(options.configPath);
|
|
97
|
+
assertApplicationCheckConfig(configValue);
|
|
98
|
+
const base = path.dirname(options.configPath);
|
|
99
|
+
const resolve = (file) => path.resolve(base, file);
|
|
100
|
+
const assembly = await readJson(resolve(configValue.assembly));
|
|
101
|
+
assertAssemblyLockfile(assembly);
|
|
102
|
+
const runtimeCapabilities = await readJson(
|
|
103
|
+
resolve(configValue.runtimeCapabilities)
|
|
104
|
+
);
|
|
105
|
+
if (!Array.isArray(runtimeCapabilities)) {
|
|
106
|
+
throw new Error("Runtime capabilities must be a JSON array.");
|
|
107
|
+
}
|
|
108
|
+
assertAssemblyRuntimeCompatible(assembly, runtimeCapabilities);
|
|
109
|
+
for (const releasePath of configValue.releases) {
|
|
110
|
+
const release = await readJson(resolve(releasePath));
|
|
111
|
+
try {
|
|
112
|
+
assertSduiReleaseIntegrity(release);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Experience release "${releasePath}" is invalid: ${error instanceof Error ? error.message : String(error)}`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
if (release.assemblyDigest !== assembly.assemblyDigest) {
|
|
119
|
+
throw new Error(
|
|
120
|
+
`Experience release "${release.document.name}@${release.document.version}" belongs to assembly "${release.assemblyDigest}", not "${assembly.assemblyDigest}".`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
application: assembly.application,
|
|
126
|
+
capabilities: assembly.capabilities.length,
|
|
127
|
+
releases: configValue.releases.length,
|
|
128
|
+
assemblyDigest: assembly.assemblyDigest
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
async function initializeCapability(options) {
|
|
132
|
+
if (!/^[a-z][a-z0-9-]*$/.test(options.namespace)) {
|
|
133
|
+
throw new Error("Capability namespace must use lowercase letters, numbers, and hyphens.");
|
|
134
|
+
}
|
|
135
|
+
const displayName = options.namespace.split("-").map((part, index) => index === 0 ? `${part.charAt(0).toUpperCase()}${part.slice(1)}` : part).join(" ");
|
|
136
|
+
const manifestPath = path.join(options.directory, "fabric.manifest.json");
|
|
137
|
+
const readmePath = path.join(options.directory, "README.md");
|
|
138
|
+
for (const file of [readmePath, manifestPath]) {
|
|
139
|
+
try {
|
|
140
|
+
await access(file);
|
|
141
|
+
throw new Error(`Refusing to overwrite existing file "${file}".`);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
if (error instanceof Error && error.message.startsWith("Refusing to overwrite")) throw error;
|
|
144
|
+
if (error.code !== "ENOENT") throw error;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const manifest = {
|
|
148
|
+
manifestVersion: 2,
|
|
149
|
+
namespace: options.namespace,
|
|
150
|
+
objectTypes: [],
|
|
151
|
+
subjectTypes: [],
|
|
152
|
+
idPrefixes: [],
|
|
153
|
+
dependencies: [],
|
|
154
|
+
policies: [],
|
|
155
|
+
eventTypes: [],
|
|
156
|
+
actions: [],
|
|
157
|
+
views: [],
|
|
158
|
+
stateMachines: [],
|
|
159
|
+
capability: {
|
|
160
|
+
displayName,
|
|
161
|
+
description: `Governed ${displayName.toLowerCase()} capability.`,
|
|
162
|
+
stability: "experimental"
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
const readme = [
|
|
166
|
+
`# ${displayName}`,
|
|
167
|
+
"",
|
|
168
|
+
"Define domain objects, governed actions, events, and projections in `fabric.manifest.json`.",
|
|
169
|
+
"",
|
|
170
|
+
"```bash",
|
|
171
|
+
"fabric-gen --input fabric.manifest.json --out generated",
|
|
172
|
+
"fabric-gen --input fabric.manifest.json --out generated --check",
|
|
173
|
+
"```",
|
|
174
|
+
""
|
|
175
|
+
].join("\n");
|
|
176
|
+
await mkdir(options.directory, { recursive: true });
|
|
177
|
+
const created = [];
|
|
178
|
+
try {
|
|
179
|
+
for (const [file, content] of [
|
|
180
|
+
[readmePath, readme],
|
|
181
|
+
[manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
182
|
+
`]
|
|
183
|
+
]) {
|
|
184
|
+
await writeFile(file, content, { encoding: "utf8", flag: "wx" });
|
|
185
|
+
created.push(file);
|
|
186
|
+
}
|
|
187
|
+
} catch (error) {
|
|
188
|
+
await Promise.all(created.map((file) => rm(file, { force: true })));
|
|
189
|
+
if (error.code === "EEXIST") {
|
|
190
|
+
throw new Error("Refusing to overwrite a file created during capability initialization.");
|
|
191
|
+
}
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
return { created };
|
|
195
|
+
}
|
|
196
|
+
async function generateFromManifest(options) {
|
|
197
|
+
const input = JSON.parse(await readFile(options.inputPath, "utf8"));
|
|
198
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("Manifest input must be a JSON object.");
|
|
199
|
+
const bundle = "modules" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };
|
|
200
|
+
const ir = compileManifestBundle(bundle);
|
|
201
|
+
const files = (await Promise.all(options.targets.map(async (name) => {
|
|
202
|
+
const target = GENERATOR_TARGETS[name];
|
|
203
|
+
if (!target) throw new Error(`Unknown generator target "${name}".`);
|
|
204
|
+
return (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));
|
|
205
|
+
}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));
|
|
206
|
+
const expected = new Set(files.map((file) => file.path));
|
|
207
|
+
const existing = await listFiles(options.outputDirectory);
|
|
208
|
+
const selectedPrefixes = options.targets.map((target) => `${target}/`);
|
|
209
|
+
const stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));
|
|
210
|
+
if (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));
|
|
211
|
+
const changed = [];
|
|
212
|
+
for (const file of files) {
|
|
213
|
+
const target = path.join(options.outputDirectory, file.path);
|
|
214
|
+
let current;
|
|
215
|
+
try {
|
|
216
|
+
current = await readFile(target, "utf8");
|
|
217
|
+
} catch {
|
|
218
|
+
current = void 0;
|
|
219
|
+
}
|
|
220
|
+
if (current !== file.content) {
|
|
221
|
+
changed.push(file.path);
|
|
222
|
+
if (!options.check) {
|
|
223
|
+
await mkdir(path.dirname(target), { recursive: true });
|
|
224
|
+
await writeFile(target, file.content, "utf8");
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(", ")}`);
|
|
229
|
+
return { changed, stale, files };
|
|
230
|
+
}
|
|
231
|
+
async function listFiles(directory, prefix = "") {
|
|
232
|
+
let entries;
|
|
233
|
+
try {
|
|
234
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
235
|
+
} catch {
|
|
236
|
+
return [];
|
|
237
|
+
}
|
|
238
|
+
const nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));
|
|
239
|
+
return nested.flat().sort();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export {
|
|
243
|
+
GENERATOR_TARGETS,
|
|
244
|
+
FabricGenUsageError,
|
|
245
|
+
fabricGenCliExitCode,
|
|
246
|
+
runFabricGenCommand,
|
|
247
|
+
checkApplication,
|
|
248
|
+
initializeCapability,
|
|
249
|
+
generateFromManifest
|
|
250
|
+
};
|
|
251
|
+
//# sourceMappingURL=chunk-CUNWMAA2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { access, mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { compileManifestBundle, runGenerator, type GeneratedFile, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport { capabilityGenerator } from \"@fabricorg/gen-capability\";\nimport { docsGenerator } from \"@fabricorg/gen-docs\";\nimport { eventsGenerator } from \"@fabricorg/gen-events\";\nimport { typesGenerator } from \"@fabricorg/gen-types\";\nimport { prismaGenerator } from \"@fabricorg/gen-prisma\";\nimport { graphqlGenerator } from \"@fabricorg/gen-graphql\";\nimport { sduiGenerator } from \"@fabricorg/gen-sdui\";\nimport { conformanceGenerator } from \"@fabricorg/gen-conformance\";\nimport {\n\tassertAssemblyLockfile,\n\tassertAssemblyRuntimeCompatible,\n\ttype AssemblyLockfile,\n\ttype AvailableCapability,\n} from \"@fabricorg/assembly\";\nimport {\n\tassertSduiReleaseIntegrity,\n\ttype SduiRelease,\n} from \"@fabricorg/sdui-release\";\n\nexport const GENERATOR_TARGETS: Record<string, GeneratorTarget> = {\n\ttypes: typesGenerator,\n\tevents: eventsGenerator,\n\tcapability: capabilityGenerator,\n\tdocs: docsGenerator,\n\tprisma: prismaGenerator,\n\tgraphql: graphqlGenerator,\n\tsdui: sduiGenerator,\n\tconformance: conformanceGenerator,\n};\nconst compareCanonicalStrings = (left: string, right: string): number => left < right ? -1 : left > right ? 1 : 0;\n\nexport interface GenerateOptions { inputPath: string; outputDirectory: string; targets: string[]; check?: boolean; }\nexport interface GenerateResult { changed: string[]; stale: string[]; files: GeneratedFile[]; }\nexport interface InitializeCapabilityOptions { directory: string; namespace: string; }\nexport interface InitializeCapabilityResult { created: string[]; }\nexport interface CheckApplicationOptions { configPath: string; }\nexport interface CheckApplicationResult {\n\tapplication: string;\n\tcapabilities: number;\n\treleases: number;\n\tassemblyDigest: string;\n}\n\nconst usage = [\n\t\"Usage:\",\n\t\" fabric-gen init capability <namespace> [--directory <path>]\",\n\t\" fabric-gen check-application [--config <path>]\",\n\t\" fabric-gen --input <manifest.json> --out <directory> [--targets <list>] [--check]\",\n].join(\"\\n\");\n\nexport class FabricGenUsageError extends Error {\n\toverride readonly name = \"FabricGenUsageError\";\n}\n\nexport function fabricGenCliExitCode(error: unknown): number {\n\treturn error instanceof FabricGenUsageError ? 2 : 1;\n}\n\nfunction flagValue(args: readonly string[], flag: string): string | undefined {\n\tconst index = args.indexOf(flag);\n\tif (index < 0) return undefined;\n\tconst value = args[index + 1];\n\tif (!value || value.startsWith(\"--\")) throw new FabricGenUsageError(usage);\n\treturn value;\n}\n\n/** Execute one CLI command and return its single human-readable result line. */\nexport async function runFabricGenCommand(args: readonly string[]): Promise<string> {\n\tif (args[0] === \"init\") {\n\t\tif (args[1] !== \"capability\" || !args[2] || args[2].startsWith(\"--\")) {\n\t\t\tthrow new FabricGenUsageError(usage);\n\t\t}\n\t\tconst namespace = args[2];\n\t\tconst directory = flagValue(args, \"--directory\") ?? namespace;\n\t\tconst result = await initializeCapability({ directory, namespace });\n\t\treturn `Initialized capability \"${namespace}\" with ${result.created.length} files.`;\n\t}\n\tif (args[0] === \"check-application\") {\n\t\tconst configPath = flagValue(args, \"--config\") ?? \"fabric.application.json\";\n\t\tconst result = await checkApplication({ configPath });\n\t\treturn `Checked \"${result.application}\": ${result.capabilities} capabilities, ${result.releases} releases.`;\n\t}\n\tconst inputPath = flagValue(args, \"--input\");\n\tconst outputDirectory = flagValue(args, \"--out\");\n\tif (!inputPath || !outputDirectory) throw new FabricGenUsageError(usage);\n\tconst result = await generateFromManifest({\n\t\tinputPath,\n\t\toutputDirectory,\n\t\ttargets: (flagValue(args, \"--targets\") ?? \"types,events,capability,docs\")\n\t\t\t.split(\",\")\n\t\t\t.filter(Boolean),\n\t\tcheck: args.includes(\"--check\"),\n\t});\n\treturn `${args.includes(\"--check\") ? \"Checked\" : \"Generated\"} ${result.files.length} files.`;\n}\n\ninterface ApplicationCheckConfig {\n\tformatVersion: 1;\n\tassembly: string;\n\truntimeCapabilities: string;\n\treleases: string[];\n}\n\nasync function readJson(file: string): Promise<unknown> {\n\treturn JSON.parse(await readFile(file, \"utf8\"));\n}\n\nfunction assertApplicationCheckConfig(value: unknown): asserts value is ApplicationCheckConfig {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Application check configuration must be a JSON object.\");\n\t}\n\tconst config = value as Record<string, unknown>;\n\tif (config.formatVersion !== 1) throw new Error(\"Application check configuration formatVersion must be 1.\");\n\tif (typeof config.assembly !== \"string\" || !config.assembly) {\n\t\tthrow new Error(\"Application check configuration assembly must be a file path.\");\n\t}\n\tif (typeof config.runtimeCapabilities !== \"string\" || !config.runtimeCapabilities) {\n\t\tthrow new Error(\"Application check configuration runtimeCapabilities must be a file path.\");\n\t}\n\tif (!Array.isArray(config.releases) || !config.releases.every((entry) => typeof entry === \"string\" && entry)) {\n\t\tthrow new Error(\"Application check configuration releases must be an array of file paths.\");\n\t}\n}\n\n/**\n * Verify an application's immutable composition inputs before deployment.\n * Every runtime capability must exactly match the approved lockfile, and every\n * promoted experience release must be intact and bound to that assembly.\n */\nexport async function checkApplication(\n\toptions: CheckApplicationOptions,\n): Promise<CheckApplicationResult> {\n\tconst configValue = await readJson(options.configPath);\n\tassertApplicationCheckConfig(configValue);\n\tconst base = path.dirname(options.configPath);\n\tconst resolve = (file: string): string => path.resolve(base, file);\n\tconst assembly = await readJson(resolve(configValue.assembly)) as AssemblyLockfile;\n\tassertAssemblyLockfile(assembly);\n\tconst runtimeCapabilities = await readJson(\n\t\tresolve(configValue.runtimeCapabilities),\n\t) as AvailableCapability[];\n\tif (!Array.isArray(runtimeCapabilities)) {\n\t\tthrow new Error(\"Runtime capabilities must be a JSON array.\");\n\t}\n\tassertAssemblyRuntimeCompatible(assembly, runtimeCapabilities);\n\tfor (const releasePath of configValue.releases) {\n\t\tconst release = await readJson(resolve(releasePath)) as SduiRelease;\n\t\ttry {\n\t\t\tassertSduiReleaseIntegrity(release);\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${releasePath}\" is invalid: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t\tif (release.assemblyDigest !== assembly.assemblyDigest) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${release.document.name}@${release.document.version}\" belongs to assembly \"${release.assemblyDigest}\", not \"${assembly.assemblyDigest}\".`,\n\t\t\t);\n\t\t}\n\t}\n\treturn {\n\t\tapplication: assembly.application,\n\t\tcapabilities: assembly.capabilities.length,\n\t\treleases: configValue.releases.length,\n\t\tassemblyDigest: assembly.assemblyDigest,\n\t};\n}\n\n/**\n * Create the smallest useful capability source tree. The manifest is accepted\n * by the compiler immediately, while leaving domain vocabulary to the adopter.\n */\nexport async function initializeCapability(\n\toptions: InitializeCapabilityOptions,\n): Promise<InitializeCapabilityResult> {\n\tif (!/^[a-z][a-z0-9-]*$/.test(options.namespace)) {\n\t\tthrow new Error(\"Capability namespace must use lowercase letters, numbers, and hyphens.\");\n\t}\n\tconst displayName = options.namespace\n\t\t.split(\"-\")\n\t\t.map((part, index) => index === 0\n\t\t\t? `${part.charAt(0).toUpperCase()}${part.slice(1)}`\n\t\t\t: part)\n\t\t.join(\" \");\n\tconst manifestPath = path.join(options.directory, \"fabric.manifest.json\");\n\tconst readmePath = path.join(options.directory, \"README.md\");\n\tfor (const file of [readmePath, manifestPath]) {\n\t\ttry {\n\t\t\tawait access(file);\n\t\t\tthrow new Error(`Refusing to overwrite existing file \"${file}\".`);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message.startsWith(\"Refusing to overwrite\")) throw error;\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\t}\n\t}\n\tconst manifest = {\n\t\tmanifestVersion: 2,\n\t\tnamespace: options.namespace,\n\t\tobjectTypes: [],\n\t\tsubjectTypes: [],\n\t\tidPrefixes: [],\n\t\tdependencies: [],\n\t\tpolicies: [],\n\t\teventTypes: [],\n\t\tactions: [],\n\t\tviews: [],\n\t\tstateMachines: [],\n\t\tcapability: {\n\t\t\tdisplayName,\n\t\t\tdescription: `Governed ${displayName.toLowerCase()} capability.`,\n\t\t\tstability: \"experimental\",\n\t\t},\n\t};\n\tconst readme = [\n\t\t`# ${displayName}`,\n\t\t\"\",\n\t\t\"Define domain objects, governed actions, events, and projections in `fabric.manifest.json`.\",\n\t\t\"\",\n\t\t\"```bash\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated --check\",\n\t\t\"```\",\n\t\t\"\",\n\t].join(\"\\n\");\n\tawait mkdir(options.directory, { recursive: true });\n\tconst created: string[] = [];\n\ttry {\n\t\tfor (const [file, content] of [\n\t\t\t[readmePath, readme],\n\t\t\t[manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`],\n\t\t] as const) {\n\t\t\tawait writeFile(file, content, { encoding: \"utf8\", flag: \"wx\" });\n\t\t\tcreated.push(file);\n\t\t}\n\t} catch (error) {\n\t\tawait Promise.all(created.map((file) => rm(file, { force: true })));\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\tthrow new Error(\"Refusing to overwrite a file created during capability initialization.\");\n\t\t}\n\t\tthrow error;\n\t}\n\treturn { created };\n}\n\nexport async function generateFromManifest(options: GenerateOptions): Promise<GenerateResult> {\n\tconst input = JSON.parse(await readFile(options.inputPath, \"utf8\"));\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) throw new Error(\"Manifest input must be a JSON object.\");\n\tconst bundle = \"modules\" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };\n\tconst ir = compileManifestBundle(bundle);\n\tconst files = (await Promise.all(options.targets.map(async (name) => {\n\t\tconst target = GENERATOR_TARGETS[name];\n\t\tif (!target) throw new Error(`Unknown generator target \"${name}\".`);\n\t\treturn (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));\n\t}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));\n\tconst expected = new Set(files.map((file) => file.path));\n\tconst existing = await listFiles(options.outputDirectory);\n\tconst selectedPrefixes = options.targets.map((target) => `${target}/`);\n\tconst stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));\n\tif (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));\n\tconst changed: string[] = [];\n\tfor (const file of files) {\n\t\tconst target = path.join(options.outputDirectory, file.path);\n\t\tlet current: string | undefined;\n\t\ttry { current = await readFile(target, \"utf8\"); } catch { current = undefined; }\n\t\tif (current !== file.content) {\n\t\t\tchanged.push(file.path);\n\t\t\tif (!options.check) { await mkdir(path.dirname(target), { recursive: true }); await writeFile(target, file.content, \"utf8\"); }\n\t\t}\n\t}\n\tif (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(\", \")}`);\n\treturn { changed, stale, files };\n}\n\nasync function listFiles(directory: string, prefix = \"\"): Promise<string[]> {\n\tlet entries;\n\ttry { entries = await readdir(directory, { withFileTypes: true }); } catch { return []; }\n\tconst nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));\n\treturn nested.flat().sort();\n}\n"],"mappings":"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","names":["result"]}
|
package/dist/cli.cjs
CHANGED
|
@@ -35,6 +35,8 @@ var import_gen_prisma = require("@fabricorg/gen-prisma");
|
|
|
35
35
|
var import_gen_graphql = require("@fabricorg/gen-graphql");
|
|
36
36
|
var import_gen_sdui = require("@fabricorg/gen-sdui");
|
|
37
37
|
var import_gen_conformance = require("@fabricorg/gen-conformance");
|
|
38
|
+
var import_assembly = require("@fabricorg/assembly");
|
|
39
|
+
var import_sdui_release = require("@fabricorg/sdui-release");
|
|
38
40
|
var GENERATOR_TARGETS = {
|
|
39
41
|
types: import_gen_types.typesGenerator,
|
|
40
42
|
events: import_gen_events.eventsGenerator,
|
|
@@ -46,6 +48,171 @@ var GENERATOR_TARGETS = {
|
|
|
46
48
|
conformance: import_gen_conformance.conformanceGenerator
|
|
47
49
|
};
|
|
48
50
|
var compareCanonicalStrings = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
51
|
+
var usage = [
|
|
52
|
+
"Usage:",
|
|
53
|
+
" fabric-gen init capability <namespace> [--directory <path>]",
|
|
54
|
+
" fabric-gen check-application [--config <path>]",
|
|
55
|
+
" fabric-gen --input <manifest.json> --out <directory> [--targets <list>] [--check]"
|
|
56
|
+
].join("\n");
|
|
57
|
+
var FabricGenUsageError = class extends Error {
|
|
58
|
+
name = "FabricGenUsageError";
|
|
59
|
+
};
|
|
60
|
+
function fabricGenCliExitCode(error) {
|
|
61
|
+
return error instanceof FabricGenUsageError ? 2 : 1;
|
|
62
|
+
}
|
|
63
|
+
function flagValue(args2, flag) {
|
|
64
|
+
const index = args2.indexOf(flag);
|
|
65
|
+
if (index < 0) return void 0;
|
|
66
|
+
const value = args2[index + 1];
|
|
67
|
+
if (!value || value.startsWith("--")) throw new FabricGenUsageError(usage);
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
async function runFabricGenCommand(args2) {
|
|
71
|
+
if (args2[0] === "init") {
|
|
72
|
+
if (args2[1] !== "capability" || !args2[2] || args2[2].startsWith("--")) {
|
|
73
|
+
throw new FabricGenUsageError(usage);
|
|
74
|
+
}
|
|
75
|
+
const namespace = args2[2];
|
|
76
|
+
const directory = flagValue(args2, "--directory") ?? namespace;
|
|
77
|
+
const result2 = await initializeCapability({ directory, namespace });
|
|
78
|
+
return `Initialized capability "${namespace}" with ${result2.created.length} files.`;
|
|
79
|
+
}
|
|
80
|
+
if (args2[0] === "check-application") {
|
|
81
|
+
const configPath = flagValue(args2, "--config") ?? "fabric.application.json";
|
|
82
|
+
const result2 = await checkApplication({ configPath });
|
|
83
|
+
return `Checked "${result2.application}": ${result2.capabilities} capabilities, ${result2.releases} releases.`;
|
|
84
|
+
}
|
|
85
|
+
const inputPath = flagValue(args2, "--input");
|
|
86
|
+
const outputDirectory = flagValue(args2, "--out");
|
|
87
|
+
if (!inputPath || !outputDirectory) throw new FabricGenUsageError(usage);
|
|
88
|
+
const result = await generateFromManifest({
|
|
89
|
+
inputPath,
|
|
90
|
+
outputDirectory,
|
|
91
|
+
targets: (flagValue(args2, "--targets") ?? "types,events,capability,docs").split(",").filter(Boolean),
|
|
92
|
+
check: args2.includes("--check")
|
|
93
|
+
});
|
|
94
|
+
return `${args2.includes("--check") ? "Checked" : "Generated"} ${result.files.length} files.`;
|
|
95
|
+
}
|
|
96
|
+
async function readJson(file) {
|
|
97
|
+
return JSON.parse(await (0, import_promises.readFile)(file, "utf8"));
|
|
98
|
+
}
|
|
99
|
+
function assertApplicationCheckConfig(value) {
|
|
100
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
101
|
+
throw new Error("Application check configuration must be a JSON object.");
|
|
102
|
+
}
|
|
103
|
+
const config = value;
|
|
104
|
+
if (config.formatVersion !== 1) throw new Error("Application check configuration formatVersion must be 1.");
|
|
105
|
+
if (typeof config.assembly !== "string" || !config.assembly) {
|
|
106
|
+
throw new Error("Application check configuration assembly must be a file path.");
|
|
107
|
+
}
|
|
108
|
+
if (typeof config.runtimeCapabilities !== "string" || !config.runtimeCapabilities) {
|
|
109
|
+
throw new Error("Application check configuration runtimeCapabilities must be a file path.");
|
|
110
|
+
}
|
|
111
|
+
if (!Array.isArray(config.releases) || !config.releases.every((entry) => typeof entry === "string" && entry)) {
|
|
112
|
+
throw new Error("Application check configuration releases must be an array of file paths.");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
async function checkApplication(options) {
|
|
116
|
+
const configValue = await readJson(options.configPath);
|
|
117
|
+
assertApplicationCheckConfig(configValue);
|
|
118
|
+
const base = import_node_path.default.dirname(options.configPath);
|
|
119
|
+
const resolve = (file) => import_node_path.default.resolve(base, file);
|
|
120
|
+
const assembly = await readJson(resolve(configValue.assembly));
|
|
121
|
+
(0, import_assembly.assertAssemblyLockfile)(assembly);
|
|
122
|
+
const runtimeCapabilities = await readJson(
|
|
123
|
+
resolve(configValue.runtimeCapabilities)
|
|
124
|
+
);
|
|
125
|
+
if (!Array.isArray(runtimeCapabilities)) {
|
|
126
|
+
throw new Error("Runtime capabilities must be a JSON array.");
|
|
127
|
+
}
|
|
128
|
+
(0, import_assembly.assertAssemblyRuntimeCompatible)(assembly, runtimeCapabilities);
|
|
129
|
+
for (const releasePath of configValue.releases) {
|
|
130
|
+
const release = await readJson(resolve(releasePath));
|
|
131
|
+
try {
|
|
132
|
+
(0, import_sdui_release.assertSduiReleaseIntegrity)(release);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`Experience release "${releasePath}" is invalid: ${error instanceof Error ? error.message : String(error)}`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
if (release.assemblyDigest !== assembly.assemblyDigest) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
`Experience release "${release.document.name}@${release.document.version}" belongs to assembly "${release.assemblyDigest}", not "${assembly.assemblyDigest}".`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
application: assembly.application,
|
|
146
|
+
capabilities: assembly.capabilities.length,
|
|
147
|
+
releases: configValue.releases.length,
|
|
148
|
+
assemblyDigest: assembly.assemblyDigest
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
async function initializeCapability(options) {
|
|
152
|
+
if (!/^[a-z][a-z0-9-]*$/.test(options.namespace)) {
|
|
153
|
+
throw new Error("Capability namespace must use lowercase letters, numbers, and hyphens.");
|
|
154
|
+
}
|
|
155
|
+
const displayName = options.namespace.split("-").map((part, index) => index === 0 ? `${part.charAt(0).toUpperCase()}${part.slice(1)}` : part).join(" ");
|
|
156
|
+
const manifestPath = import_node_path.default.join(options.directory, "fabric.manifest.json");
|
|
157
|
+
const readmePath = import_node_path.default.join(options.directory, "README.md");
|
|
158
|
+
for (const file of [readmePath, manifestPath]) {
|
|
159
|
+
try {
|
|
160
|
+
await (0, import_promises.access)(file);
|
|
161
|
+
throw new Error(`Refusing to overwrite existing file "${file}".`);
|
|
162
|
+
} catch (error) {
|
|
163
|
+
if (error instanceof Error && error.message.startsWith("Refusing to overwrite")) throw error;
|
|
164
|
+
if (error.code !== "ENOENT") throw error;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const manifest = {
|
|
168
|
+
manifestVersion: 2,
|
|
169
|
+
namespace: options.namespace,
|
|
170
|
+
objectTypes: [],
|
|
171
|
+
subjectTypes: [],
|
|
172
|
+
idPrefixes: [],
|
|
173
|
+
dependencies: [],
|
|
174
|
+
policies: [],
|
|
175
|
+
eventTypes: [],
|
|
176
|
+
actions: [],
|
|
177
|
+
views: [],
|
|
178
|
+
stateMachines: [],
|
|
179
|
+
capability: {
|
|
180
|
+
displayName,
|
|
181
|
+
description: `Governed ${displayName.toLowerCase()} capability.`,
|
|
182
|
+
stability: "experimental"
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
const readme = [
|
|
186
|
+
`# ${displayName}`,
|
|
187
|
+
"",
|
|
188
|
+
"Define domain objects, governed actions, events, and projections in `fabric.manifest.json`.",
|
|
189
|
+
"",
|
|
190
|
+
"```bash",
|
|
191
|
+
"fabric-gen --input fabric.manifest.json --out generated",
|
|
192
|
+
"fabric-gen --input fabric.manifest.json --out generated --check",
|
|
193
|
+
"```",
|
|
194
|
+
""
|
|
195
|
+
].join("\n");
|
|
196
|
+
await (0, import_promises.mkdir)(options.directory, { recursive: true });
|
|
197
|
+
const created = [];
|
|
198
|
+
try {
|
|
199
|
+
for (const [file, content] of [
|
|
200
|
+
[readmePath, readme],
|
|
201
|
+
[manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
202
|
+
`]
|
|
203
|
+
]) {
|
|
204
|
+
await (0, import_promises.writeFile)(file, content, { encoding: "utf8", flag: "wx" });
|
|
205
|
+
created.push(file);
|
|
206
|
+
}
|
|
207
|
+
} catch (error) {
|
|
208
|
+
await Promise.all(created.map((file) => (0, import_promises.rm)(file, { force: true })));
|
|
209
|
+
if (error.code === "EEXIST") {
|
|
210
|
+
throw new Error("Refusing to overwrite a file created during capability initialization.");
|
|
211
|
+
}
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
return { created };
|
|
215
|
+
}
|
|
49
216
|
async function generateFromManifest(options) {
|
|
50
217
|
const input = JSON.parse(await (0, import_promises.readFile)(options.inputPath, "utf8"));
|
|
51
218
|
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("Manifest input must be a JSON object.");
|
|
@@ -94,19 +261,8 @@ async function listFiles(directory, prefix = "") {
|
|
|
94
261
|
|
|
95
262
|
// cli.ts
|
|
96
263
|
var args = process.argv.slice(2);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
};
|
|
101
|
-
var inputPath = value("--input");
|
|
102
|
-
var outputDirectory = value("--out");
|
|
103
|
-
if (!inputPath || !outputDirectory) {
|
|
104
|
-
console.error("Usage: fabric-gen --input manifest.json --out generated [--targets types,events,capability,docs] [--check]");
|
|
105
|
-
process.exitCode = 2;
|
|
106
|
-
} else {
|
|
107
|
-
generateFromManifest({ inputPath, outputDirectory, targets: (value("--targets") ?? "types,events,capability,docs").split(",").filter(Boolean), check: args.includes("--check") }).then((result) => console.log(`${args.includes("--check") ? "Checked" : "Generated"} ${result.files.length} files.`)).catch((error) => {
|
|
108
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
109
|
-
process.exitCode = 1;
|
|
110
|
-
});
|
|
111
|
-
}
|
|
264
|
+
runFabricGenCommand(args).then((message) => console.log(message)).catch((error) => {
|
|
265
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
266
|
+
process.exitCode = fabricGenCliExitCode(error);
|
|
267
|
+
});
|
|
112
268
|
//# sourceMappingURL=cli.cjs.map
|
package/dist/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts","../cli.ts"],"sourcesContent":["import { mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { compileManifestBundle, runGenerator, type GeneratedFile, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport { capabilityGenerator } from \"@fabricorg/gen-capability\";\nimport { docsGenerator } from \"@fabricorg/gen-docs\";\nimport { eventsGenerator } from \"@fabricorg/gen-events\";\nimport { typesGenerator } from \"@fabricorg/gen-types\";\nimport { prismaGenerator } from \"@fabricorg/gen-prisma\";\nimport { graphqlGenerator } from \"@fabricorg/gen-graphql\";\nimport { sduiGenerator } from \"@fabricorg/gen-sdui\";\nimport { conformanceGenerator } from \"@fabricorg/gen-conformance\";\n\nexport const GENERATOR_TARGETS: Record<string, GeneratorTarget> = {\n\ttypes: typesGenerator,\n\tevents: eventsGenerator,\n\tcapability: capabilityGenerator,\n\tdocs: docsGenerator,\n\tprisma: prismaGenerator,\n\tgraphql: graphqlGenerator,\n\tsdui: sduiGenerator,\n\tconformance: conformanceGenerator,\n};\nconst compareCanonicalStrings = (left: string, right: string): number => left < right ? -1 : left > right ? 1 : 0;\n\nexport interface GenerateOptions { inputPath: string; outputDirectory: string; targets: string[]; check?: boolean; }\nexport interface GenerateResult { changed: string[]; stale: string[]; files: GeneratedFile[]; }\n\nexport async function generateFromManifest(options: GenerateOptions): Promise<GenerateResult> {\n\tconst input = JSON.parse(await readFile(options.inputPath, \"utf8\"));\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) throw new Error(\"Manifest input must be a JSON object.\");\n\tconst bundle = \"modules\" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };\n\tconst ir = compileManifestBundle(bundle);\n\tconst files = (await Promise.all(options.targets.map(async (name) => {\n\t\tconst target = GENERATOR_TARGETS[name];\n\t\tif (!target) throw new Error(`Unknown generator target \"${name}\".`);\n\t\treturn (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));\n\t}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));\n\tconst expected = new Set(files.map((file) => file.path));\n\tconst existing = await listFiles(options.outputDirectory);\n\tconst selectedPrefixes = options.targets.map((target) => `${target}/`);\n\tconst stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));\n\tif (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));\n\tconst changed: string[] = [];\n\tfor (const file of files) {\n\t\tconst target = path.join(options.outputDirectory, file.path);\n\t\tlet current: string | undefined;\n\t\ttry { current = await readFile(target, \"utf8\"); } catch { current = undefined; }\n\t\tif (current !== file.content) {\n\t\t\tchanged.push(file.path);\n\t\t\tif (!options.check) { await mkdir(path.dirname(target), { recursive: true }); await writeFile(target, file.content, \"utf8\"); }\n\t\t}\n\t}\n\tif (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(\", \")}`);\n\treturn { changed, stale, files };\n}\n\nasync function listFiles(directory: string, prefix = \"\"): Promise<string[]> {\n\tlet entries;\n\ttry { entries = await readdir(directory, { withFileTypes: true }); } catch { return []; }\n\tconst nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));\n\treturn nested.flat().sort();\n}\n","#!/usr/bin/env node\nimport { generateFromManifest } from \"./index\";\n\nconst args = process.argv.slice(2);\nconst value = (flag: string): string | undefined => { const index = args.indexOf(flag); return index >= 0 ? args[index + 1] : undefined; };\nconst inputPath = value(\"--input\");\nconst outputDirectory = value(\"--out\");\nif (!inputPath || !outputDirectory) {\n\tconsole.error(\"Usage: fabric-gen --input manifest.json --out generated [--targets types,events,capability,docs] [--check]\");\n\tprocess.exitCode = 2;\n} else {\n\tgenerateFromManifest({ inputPath, outputDirectory, targets: (value(\"--targets\") ?? \"types,events,capability,docs\").split(\",\").filter(Boolean), check: args.includes(\"--check\") })\n\t\t.then((result) => console.log(`${args.includes(\"--check\") ? \"Checked\" : \"Generated\"} ${result.files.length} files.`))\n\t\t.catch((error: unknown) => { console.error(error instanceof Error ? error.message : String(error)); process.exitCode = 1; });\n}\n"],"mappings":"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","names":["path"]}
|
|
1
|
+
{"version":3,"sources":["../index.ts","../cli.ts"],"sourcesContent":["import { access, mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { compileManifestBundle, runGenerator, type GeneratedFile, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport { capabilityGenerator } from \"@fabricorg/gen-capability\";\nimport { docsGenerator } from \"@fabricorg/gen-docs\";\nimport { eventsGenerator } from \"@fabricorg/gen-events\";\nimport { typesGenerator } from \"@fabricorg/gen-types\";\nimport { prismaGenerator } from \"@fabricorg/gen-prisma\";\nimport { graphqlGenerator } from \"@fabricorg/gen-graphql\";\nimport { sduiGenerator } from \"@fabricorg/gen-sdui\";\nimport { conformanceGenerator } from \"@fabricorg/gen-conformance\";\nimport {\n\tassertAssemblyLockfile,\n\tassertAssemblyRuntimeCompatible,\n\ttype AssemblyLockfile,\n\ttype AvailableCapability,\n} from \"@fabricorg/assembly\";\nimport {\n\tassertSduiReleaseIntegrity,\n\ttype SduiRelease,\n} from \"@fabricorg/sdui-release\";\n\nexport const GENERATOR_TARGETS: Record<string, GeneratorTarget> = {\n\ttypes: typesGenerator,\n\tevents: eventsGenerator,\n\tcapability: capabilityGenerator,\n\tdocs: docsGenerator,\n\tprisma: prismaGenerator,\n\tgraphql: graphqlGenerator,\n\tsdui: sduiGenerator,\n\tconformance: conformanceGenerator,\n};\nconst compareCanonicalStrings = (left: string, right: string): number => left < right ? -1 : left > right ? 1 : 0;\n\nexport interface GenerateOptions { inputPath: string; outputDirectory: string; targets: string[]; check?: boolean; }\nexport interface GenerateResult { changed: string[]; stale: string[]; files: GeneratedFile[]; }\nexport interface InitializeCapabilityOptions { directory: string; namespace: string; }\nexport interface InitializeCapabilityResult { created: string[]; }\nexport interface CheckApplicationOptions { configPath: string; }\nexport interface CheckApplicationResult {\n\tapplication: string;\n\tcapabilities: number;\n\treleases: number;\n\tassemblyDigest: string;\n}\n\nconst usage = [\n\t\"Usage:\",\n\t\" fabric-gen init capability <namespace> [--directory <path>]\",\n\t\" fabric-gen check-application [--config <path>]\",\n\t\" fabric-gen --input <manifest.json> --out <directory> [--targets <list>] [--check]\",\n].join(\"\\n\");\n\nexport class FabricGenUsageError extends Error {\n\toverride readonly name = \"FabricGenUsageError\";\n}\n\nexport function fabricGenCliExitCode(error: unknown): number {\n\treturn error instanceof FabricGenUsageError ? 2 : 1;\n}\n\nfunction flagValue(args: readonly string[], flag: string): string | undefined {\n\tconst index = args.indexOf(flag);\n\tif (index < 0) return undefined;\n\tconst value = args[index + 1];\n\tif (!value || value.startsWith(\"--\")) throw new FabricGenUsageError(usage);\n\treturn value;\n}\n\n/** Execute one CLI command and return its single human-readable result line. */\nexport async function runFabricGenCommand(args: readonly string[]): Promise<string> {\n\tif (args[0] === \"init\") {\n\t\tif (args[1] !== \"capability\" || !args[2] || args[2].startsWith(\"--\")) {\n\t\t\tthrow new FabricGenUsageError(usage);\n\t\t}\n\t\tconst namespace = args[2];\n\t\tconst directory = flagValue(args, \"--directory\") ?? namespace;\n\t\tconst result = await initializeCapability({ directory, namespace });\n\t\treturn `Initialized capability \"${namespace}\" with ${result.created.length} files.`;\n\t}\n\tif (args[0] === \"check-application\") {\n\t\tconst configPath = flagValue(args, \"--config\") ?? \"fabric.application.json\";\n\t\tconst result = await checkApplication({ configPath });\n\t\treturn `Checked \"${result.application}\": ${result.capabilities} capabilities, ${result.releases} releases.`;\n\t}\n\tconst inputPath = flagValue(args, \"--input\");\n\tconst outputDirectory = flagValue(args, \"--out\");\n\tif (!inputPath || !outputDirectory) throw new FabricGenUsageError(usage);\n\tconst result = await generateFromManifest({\n\t\tinputPath,\n\t\toutputDirectory,\n\t\ttargets: (flagValue(args, \"--targets\") ?? \"types,events,capability,docs\")\n\t\t\t.split(\",\")\n\t\t\t.filter(Boolean),\n\t\tcheck: args.includes(\"--check\"),\n\t});\n\treturn `${args.includes(\"--check\") ? \"Checked\" : \"Generated\"} ${result.files.length} files.`;\n}\n\ninterface ApplicationCheckConfig {\n\tformatVersion: 1;\n\tassembly: string;\n\truntimeCapabilities: string;\n\treleases: string[];\n}\n\nasync function readJson(file: string): Promise<unknown> {\n\treturn JSON.parse(await readFile(file, \"utf8\"));\n}\n\nfunction assertApplicationCheckConfig(value: unknown): asserts value is ApplicationCheckConfig {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Application check configuration must be a JSON object.\");\n\t}\n\tconst config = value as Record<string, unknown>;\n\tif (config.formatVersion !== 1) throw new Error(\"Application check configuration formatVersion must be 1.\");\n\tif (typeof config.assembly !== \"string\" || !config.assembly) {\n\t\tthrow new Error(\"Application check configuration assembly must be a file path.\");\n\t}\n\tif (typeof config.runtimeCapabilities !== \"string\" || !config.runtimeCapabilities) {\n\t\tthrow new Error(\"Application check configuration runtimeCapabilities must be a file path.\");\n\t}\n\tif (!Array.isArray(config.releases) || !config.releases.every((entry) => typeof entry === \"string\" && entry)) {\n\t\tthrow new Error(\"Application check configuration releases must be an array of file paths.\");\n\t}\n}\n\n/**\n * Verify an application's immutable composition inputs before deployment.\n * Every runtime capability must exactly match the approved lockfile, and every\n * promoted experience release must be intact and bound to that assembly.\n */\nexport async function checkApplication(\n\toptions: CheckApplicationOptions,\n): Promise<CheckApplicationResult> {\n\tconst configValue = await readJson(options.configPath);\n\tassertApplicationCheckConfig(configValue);\n\tconst base = path.dirname(options.configPath);\n\tconst resolve = (file: string): string => path.resolve(base, file);\n\tconst assembly = await readJson(resolve(configValue.assembly)) as AssemblyLockfile;\n\tassertAssemblyLockfile(assembly);\n\tconst runtimeCapabilities = await readJson(\n\t\tresolve(configValue.runtimeCapabilities),\n\t) as AvailableCapability[];\n\tif (!Array.isArray(runtimeCapabilities)) {\n\t\tthrow new Error(\"Runtime capabilities must be a JSON array.\");\n\t}\n\tassertAssemblyRuntimeCompatible(assembly, runtimeCapabilities);\n\tfor (const releasePath of configValue.releases) {\n\t\tconst release = await readJson(resolve(releasePath)) as SduiRelease;\n\t\ttry {\n\t\t\tassertSduiReleaseIntegrity(release);\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${releasePath}\" is invalid: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t\tif (release.assemblyDigest !== assembly.assemblyDigest) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${release.document.name}@${release.document.version}\" belongs to assembly \"${release.assemblyDigest}\", not \"${assembly.assemblyDigest}\".`,\n\t\t\t);\n\t\t}\n\t}\n\treturn {\n\t\tapplication: assembly.application,\n\t\tcapabilities: assembly.capabilities.length,\n\t\treleases: configValue.releases.length,\n\t\tassemblyDigest: assembly.assemblyDigest,\n\t};\n}\n\n/**\n * Create the smallest useful capability source tree. The manifest is accepted\n * by the compiler immediately, while leaving domain vocabulary to the adopter.\n */\nexport async function initializeCapability(\n\toptions: InitializeCapabilityOptions,\n): Promise<InitializeCapabilityResult> {\n\tif (!/^[a-z][a-z0-9-]*$/.test(options.namespace)) {\n\t\tthrow new Error(\"Capability namespace must use lowercase letters, numbers, and hyphens.\");\n\t}\n\tconst displayName = options.namespace\n\t\t.split(\"-\")\n\t\t.map((part, index) => index === 0\n\t\t\t? `${part.charAt(0).toUpperCase()}${part.slice(1)}`\n\t\t\t: part)\n\t\t.join(\" \");\n\tconst manifestPath = path.join(options.directory, \"fabric.manifest.json\");\n\tconst readmePath = path.join(options.directory, \"README.md\");\n\tfor (const file of [readmePath, manifestPath]) {\n\t\ttry {\n\t\t\tawait access(file);\n\t\t\tthrow new Error(`Refusing to overwrite existing file \"${file}\".`);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message.startsWith(\"Refusing to overwrite\")) throw error;\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\t}\n\t}\n\tconst manifest = {\n\t\tmanifestVersion: 2,\n\t\tnamespace: options.namespace,\n\t\tobjectTypes: [],\n\t\tsubjectTypes: [],\n\t\tidPrefixes: [],\n\t\tdependencies: [],\n\t\tpolicies: [],\n\t\teventTypes: [],\n\t\tactions: [],\n\t\tviews: [],\n\t\tstateMachines: [],\n\t\tcapability: {\n\t\t\tdisplayName,\n\t\t\tdescription: `Governed ${displayName.toLowerCase()} capability.`,\n\t\t\tstability: \"experimental\",\n\t\t},\n\t};\n\tconst readme = [\n\t\t`# ${displayName}`,\n\t\t\"\",\n\t\t\"Define domain objects, governed actions, events, and projections in `fabric.manifest.json`.\",\n\t\t\"\",\n\t\t\"```bash\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated --check\",\n\t\t\"```\",\n\t\t\"\",\n\t].join(\"\\n\");\n\tawait mkdir(options.directory, { recursive: true });\n\tconst created: string[] = [];\n\ttry {\n\t\tfor (const [file, content] of [\n\t\t\t[readmePath, readme],\n\t\t\t[manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`],\n\t\t] as const) {\n\t\t\tawait writeFile(file, content, { encoding: \"utf8\", flag: \"wx\" });\n\t\t\tcreated.push(file);\n\t\t}\n\t} catch (error) {\n\t\tawait Promise.all(created.map((file) => rm(file, { force: true })));\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\tthrow new Error(\"Refusing to overwrite a file created during capability initialization.\");\n\t\t}\n\t\tthrow error;\n\t}\n\treturn { created };\n}\n\nexport async function generateFromManifest(options: GenerateOptions): Promise<GenerateResult> {\n\tconst input = JSON.parse(await readFile(options.inputPath, \"utf8\"));\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) throw new Error(\"Manifest input must be a JSON object.\");\n\tconst bundle = \"modules\" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };\n\tconst ir = compileManifestBundle(bundle);\n\tconst files = (await Promise.all(options.targets.map(async (name) => {\n\t\tconst target = GENERATOR_TARGETS[name];\n\t\tif (!target) throw new Error(`Unknown generator target \"${name}\".`);\n\t\treturn (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));\n\t}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));\n\tconst expected = new Set(files.map((file) => file.path));\n\tconst existing = await listFiles(options.outputDirectory);\n\tconst selectedPrefixes = options.targets.map((target) => `${target}/`);\n\tconst stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));\n\tif (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));\n\tconst changed: string[] = [];\n\tfor (const file of files) {\n\t\tconst target = path.join(options.outputDirectory, file.path);\n\t\tlet current: string | undefined;\n\t\ttry { current = await readFile(target, \"utf8\"); } catch { current = undefined; }\n\t\tif (current !== file.content) {\n\t\t\tchanged.push(file.path);\n\t\t\tif (!options.check) { await mkdir(path.dirname(target), { recursive: true }); await writeFile(target, file.content, \"utf8\"); }\n\t\t}\n\t}\n\tif (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(\", \")}`);\n\treturn { changed, stale, files };\n}\n\nasync function listFiles(directory: string, prefix = \"\"): Promise<string[]> {\n\tlet entries;\n\ttry { entries = await readdir(directory, { withFileTypes: true }); } catch { return []; }\n\tconst nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));\n\treturn nested.flat().sort();\n}\n","#!/usr/bin/env node\nimport { fabricGenCliExitCode, runFabricGenCommand } from \"./index\";\n\nconst args = process.argv.slice(2);\nrunFabricGenCommand(args)\n\t.then((message) => console.log(message))\n\t.catch((error: unknown) => {\n\t\tconsole.error(error instanceof Error ? error.message : String(error));\n\t\tprocess.exitCode = fabricGenCliExitCode(error);\n\t});\n"],"mappings":"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","names":["args","result","path"]}
|
package/dist/cli.js
CHANGED
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
fabricGenCliExitCode,
|
|
4
|
+
runFabricGenCommand
|
|
5
|
+
} from "./chunk-CUNWMAA2.js";
|
|
5
6
|
|
|
6
7
|
// cli.ts
|
|
7
8
|
var args = process.argv.slice(2);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
var inputPath = value("--input");
|
|
13
|
-
var outputDirectory = value("--out");
|
|
14
|
-
if (!inputPath || !outputDirectory) {
|
|
15
|
-
console.error("Usage: fabric-gen --input manifest.json --out generated [--targets types,events,capability,docs] [--check]");
|
|
16
|
-
process.exitCode = 2;
|
|
17
|
-
} else {
|
|
18
|
-
generateFromManifest({ inputPath, outputDirectory, targets: (value("--targets") ?? "types,events,capability,docs").split(",").filter(Boolean), check: args.includes("--check") }).then((result) => console.log(`${args.includes("--check") ? "Checked" : "Generated"} ${result.files.length} files.`)).catch((error) => {
|
|
19
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
20
|
-
process.exitCode = 1;
|
|
21
|
-
});
|
|
22
|
-
}
|
|
9
|
+
runFabricGenCommand(args).then((message) => console.log(message)).catch((error) => {
|
|
10
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
11
|
+
process.exitCode = fabricGenCliExitCode(error);
|
|
12
|
+
});
|
|
23
13
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport {
|
|
1
|
+
{"version":3,"sources":["../cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { fabricGenCliExitCode, runFabricGenCommand } from \"./index\";\n\nconst args = process.argv.slice(2);\nrunFabricGenCommand(args)\n\t.then((message) => console.log(message))\n\t.catch((error: unknown) => {\n\t\tconsole.error(error instanceof Error ? error.message : String(error));\n\t\tprocess.exitCode = fabricGenCliExitCode(error);\n\t});\n"],"mappings":";;;;;;;AAGA,IAAM,OAAO,QAAQ,KAAK,MAAM,CAAC;AACjC,oBAAoB,IAAI,EACtB,KAAK,CAAC,YAAY,QAAQ,IAAI,OAAO,CAAC,EACtC,MAAM,CAAC,UAAmB;AAC1B,UAAQ,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AACpE,UAAQ,WAAW,qBAAqB,KAAK;AAC9C,CAAC;","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -30,8 +30,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
FabricGenUsageError: () => FabricGenUsageError,
|
|
33
34
|
GENERATOR_TARGETS: () => GENERATOR_TARGETS,
|
|
34
|
-
|
|
35
|
+
checkApplication: () => checkApplication,
|
|
36
|
+
fabricGenCliExitCode: () => fabricGenCliExitCode,
|
|
37
|
+
generateFromManifest: () => generateFromManifest,
|
|
38
|
+
initializeCapability: () => initializeCapability,
|
|
39
|
+
runFabricGenCommand: () => runFabricGenCommand
|
|
35
40
|
});
|
|
36
41
|
module.exports = __toCommonJS(index_exports);
|
|
37
42
|
var import_promises = require("fs/promises");
|
|
@@ -45,6 +50,8 @@ var import_gen_prisma = require("@fabricorg/gen-prisma");
|
|
|
45
50
|
var import_gen_graphql = require("@fabricorg/gen-graphql");
|
|
46
51
|
var import_gen_sdui = require("@fabricorg/gen-sdui");
|
|
47
52
|
var import_gen_conformance = require("@fabricorg/gen-conformance");
|
|
53
|
+
var import_assembly = require("@fabricorg/assembly");
|
|
54
|
+
var import_sdui_release = require("@fabricorg/sdui-release");
|
|
48
55
|
var GENERATOR_TARGETS = {
|
|
49
56
|
types: import_gen_types.typesGenerator,
|
|
50
57
|
events: import_gen_events.eventsGenerator,
|
|
@@ -56,6 +63,171 @@ var GENERATOR_TARGETS = {
|
|
|
56
63
|
conformance: import_gen_conformance.conformanceGenerator
|
|
57
64
|
};
|
|
58
65
|
var compareCanonicalStrings = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
66
|
+
var usage = [
|
|
67
|
+
"Usage:",
|
|
68
|
+
" fabric-gen init capability <namespace> [--directory <path>]",
|
|
69
|
+
" fabric-gen check-application [--config <path>]",
|
|
70
|
+
" fabric-gen --input <manifest.json> --out <directory> [--targets <list>] [--check]"
|
|
71
|
+
].join("\n");
|
|
72
|
+
var FabricGenUsageError = class extends Error {
|
|
73
|
+
name = "FabricGenUsageError";
|
|
74
|
+
};
|
|
75
|
+
function fabricGenCliExitCode(error) {
|
|
76
|
+
return error instanceof FabricGenUsageError ? 2 : 1;
|
|
77
|
+
}
|
|
78
|
+
function flagValue(args, flag) {
|
|
79
|
+
const index = args.indexOf(flag);
|
|
80
|
+
if (index < 0) return void 0;
|
|
81
|
+
const value = args[index + 1];
|
|
82
|
+
if (!value || value.startsWith("--")) throw new FabricGenUsageError(usage);
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
async function runFabricGenCommand(args) {
|
|
86
|
+
if (args[0] === "init") {
|
|
87
|
+
if (args[1] !== "capability" || !args[2] || args[2].startsWith("--")) {
|
|
88
|
+
throw new FabricGenUsageError(usage);
|
|
89
|
+
}
|
|
90
|
+
const namespace = args[2];
|
|
91
|
+
const directory = flagValue(args, "--directory") ?? namespace;
|
|
92
|
+
const result2 = await initializeCapability({ directory, namespace });
|
|
93
|
+
return `Initialized capability "${namespace}" with ${result2.created.length} files.`;
|
|
94
|
+
}
|
|
95
|
+
if (args[0] === "check-application") {
|
|
96
|
+
const configPath = flagValue(args, "--config") ?? "fabric.application.json";
|
|
97
|
+
const result2 = await checkApplication({ configPath });
|
|
98
|
+
return `Checked "${result2.application}": ${result2.capabilities} capabilities, ${result2.releases} releases.`;
|
|
99
|
+
}
|
|
100
|
+
const inputPath = flagValue(args, "--input");
|
|
101
|
+
const outputDirectory = flagValue(args, "--out");
|
|
102
|
+
if (!inputPath || !outputDirectory) throw new FabricGenUsageError(usage);
|
|
103
|
+
const result = await generateFromManifest({
|
|
104
|
+
inputPath,
|
|
105
|
+
outputDirectory,
|
|
106
|
+
targets: (flagValue(args, "--targets") ?? "types,events,capability,docs").split(",").filter(Boolean),
|
|
107
|
+
check: args.includes("--check")
|
|
108
|
+
});
|
|
109
|
+
return `${args.includes("--check") ? "Checked" : "Generated"} ${result.files.length} files.`;
|
|
110
|
+
}
|
|
111
|
+
async function readJson(file) {
|
|
112
|
+
return JSON.parse(await (0, import_promises.readFile)(file, "utf8"));
|
|
113
|
+
}
|
|
114
|
+
function assertApplicationCheckConfig(value) {
|
|
115
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
116
|
+
throw new Error("Application check configuration must be a JSON object.");
|
|
117
|
+
}
|
|
118
|
+
const config = value;
|
|
119
|
+
if (config.formatVersion !== 1) throw new Error("Application check configuration formatVersion must be 1.");
|
|
120
|
+
if (typeof config.assembly !== "string" || !config.assembly) {
|
|
121
|
+
throw new Error("Application check configuration assembly must be a file path.");
|
|
122
|
+
}
|
|
123
|
+
if (typeof config.runtimeCapabilities !== "string" || !config.runtimeCapabilities) {
|
|
124
|
+
throw new Error("Application check configuration runtimeCapabilities must be a file path.");
|
|
125
|
+
}
|
|
126
|
+
if (!Array.isArray(config.releases) || !config.releases.every((entry) => typeof entry === "string" && entry)) {
|
|
127
|
+
throw new Error("Application check configuration releases must be an array of file paths.");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function checkApplication(options) {
|
|
131
|
+
const configValue = await readJson(options.configPath);
|
|
132
|
+
assertApplicationCheckConfig(configValue);
|
|
133
|
+
const base = import_node_path.default.dirname(options.configPath);
|
|
134
|
+
const resolve = (file) => import_node_path.default.resolve(base, file);
|
|
135
|
+
const assembly = await readJson(resolve(configValue.assembly));
|
|
136
|
+
(0, import_assembly.assertAssemblyLockfile)(assembly);
|
|
137
|
+
const runtimeCapabilities = await readJson(
|
|
138
|
+
resolve(configValue.runtimeCapabilities)
|
|
139
|
+
);
|
|
140
|
+
if (!Array.isArray(runtimeCapabilities)) {
|
|
141
|
+
throw new Error("Runtime capabilities must be a JSON array.");
|
|
142
|
+
}
|
|
143
|
+
(0, import_assembly.assertAssemblyRuntimeCompatible)(assembly, runtimeCapabilities);
|
|
144
|
+
for (const releasePath of configValue.releases) {
|
|
145
|
+
const release = await readJson(resolve(releasePath));
|
|
146
|
+
try {
|
|
147
|
+
(0, import_sdui_release.assertSduiReleaseIntegrity)(release);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`Experience release "${releasePath}" is invalid: ${error instanceof Error ? error.message : String(error)}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
if (release.assemblyDigest !== assembly.assemblyDigest) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`Experience release "${release.document.name}@${release.document.version}" belongs to assembly "${release.assemblyDigest}", not "${assembly.assemblyDigest}".`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
application: assembly.application,
|
|
161
|
+
capabilities: assembly.capabilities.length,
|
|
162
|
+
releases: configValue.releases.length,
|
|
163
|
+
assemblyDigest: assembly.assemblyDigest
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
async function initializeCapability(options) {
|
|
167
|
+
if (!/^[a-z][a-z0-9-]*$/.test(options.namespace)) {
|
|
168
|
+
throw new Error("Capability namespace must use lowercase letters, numbers, and hyphens.");
|
|
169
|
+
}
|
|
170
|
+
const displayName = options.namespace.split("-").map((part, index) => index === 0 ? `${part.charAt(0).toUpperCase()}${part.slice(1)}` : part).join(" ");
|
|
171
|
+
const manifestPath = import_node_path.default.join(options.directory, "fabric.manifest.json");
|
|
172
|
+
const readmePath = import_node_path.default.join(options.directory, "README.md");
|
|
173
|
+
for (const file of [readmePath, manifestPath]) {
|
|
174
|
+
try {
|
|
175
|
+
await (0, import_promises.access)(file);
|
|
176
|
+
throw new Error(`Refusing to overwrite existing file "${file}".`);
|
|
177
|
+
} catch (error) {
|
|
178
|
+
if (error instanceof Error && error.message.startsWith("Refusing to overwrite")) throw error;
|
|
179
|
+
if (error.code !== "ENOENT") throw error;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const manifest = {
|
|
183
|
+
manifestVersion: 2,
|
|
184
|
+
namespace: options.namespace,
|
|
185
|
+
objectTypes: [],
|
|
186
|
+
subjectTypes: [],
|
|
187
|
+
idPrefixes: [],
|
|
188
|
+
dependencies: [],
|
|
189
|
+
policies: [],
|
|
190
|
+
eventTypes: [],
|
|
191
|
+
actions: [],
|
|
192
|
+
views: [],
|
|
193
|
+
stateMachines: [],
|
|
194
|
+
capability: {
|
|
195
|
+
displayName,
|
|
196
|
+
description: `Governed ${displayName.toLowerCase()} capability.`,
|
|
197
|
+
stability: "experimental"
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
const readme = [
|
|
201
|
+
`# ${displayName}`,
|
|
202
|
+
"",
|
|
203
|
+
"Define domain objects, governed actions, events, and projections in `fabric.manifest.json`.",
|
|
204
|
+
"",
|
|
205
|
+
"```bash",
|
|
206
|
+
"fabric-gen --input fabric.manifest.json --out generated",
|
|
207
|
+
"fabric-gen --input fabric.manifest.json --out generated --check",
|
|
208
|
+
"```",
|
|
209
|
+
""
|
|
210
|
+
].join("\n");
|
|
211
|
+
await (0, import_promises.mkdir)(options.directory, { recursive: true });
|
|
212
|
+
const created = [];
|
|
213
|
+
try {
|
|
214
|
+
for (const [file, content] of [
|
|
215
|
+
[readmePath, readme],
|
|
216
|
+
[manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
217
|
+
`]
|
|
218
|
+
]) {
|
|
219
|
+
await (0, import_promises.writeFile)(file, content, { encoding: "utf8", flag: "wx" });
|
|
220
|
+
created.push(file);
|
|
221
|
+
}
|
|
222
|
+
} catch (error) {
|
|
223
|
+
await Promise.all(created.map((file) => (0, import_promises.rm)(file, { force: true })));
|
|
224
|
+
if (error.code === "EEXIST") {
|
|
225
|
+
throw new Error("Refusing to overwrite a file created during capability initialization.");
|
|
226
|
+
}
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
return { created };
|
|
230
|
+
}
|
|
59
231
|
async function generateFromManifest(options) {
|
|
60
232
|
const input = JSON.parse(await (0, import_promises.readFile)(options.inputPath, "utf8"));
|
|
61
233
|
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("Manifest input must be a JSON object.");
|
|
@@ -103,7 +275,12 @@ async function listFiles(directory, prefix = "") {
|
|
|
103
275
|
}
|
|
104
276
|
// Annotate the CommonJS export names for ESM import in node:
|
|
105
277
|
0 && (module.exports = {
|
|
278
|
+
FabricGenUsageError,
|
|
106
279
|
GENERATOR_TARGETS,
|
|
107
|
-
|
|
280
|
+
checkApplication,
|
|
281
|
+
fabricGenCliExitCode,
|
|
282
|
+
generateFromManifest,
|
|
283
|
+
initializeCapability,
|
|
284
|
+
runFabricGenCommand
|
|
108
285
|
});
|
|
109
286
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { compileManifestBundle, runGenerator, type GeneratedFile, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport { capabilityGenerator } from \"@fabricorg/gen-capability\";\nimport { docsGenerator } from \"@fabricorg/gen-docs\";\nimport { eventsGenerator } from \"@fabricorg/gen-events\";\nimport { typesGenerator } from \"@fabricorg/gen-types\";\nimport { prismaGenerator } from \"@fabricorg/gen-prisma\";\nimport { graphqlGenerator } from \"@fabricorg/gen-graphql\";\nimport { sduiGenerator } from \"@fabricorg/gen-sdui\";\nimport { conformanceGenerator } from \"@fabricorg/gen-conformance\";\n\nexport const GENERATOR_TARGETS: Record<string, GeneratorTarget> = {\n\ttypes: typesGenerator,\n\tevents: eventsGenerator,\n\tcapability: capabilityGenerator,\n\tdocs: docsGenerator,\n\tprisma: prismaGenerator,\n\tgraphql: graphqlGenerator,\n\tsdui: sduiGenerator,\n\tconformance: conformanceGenerator,\n};\nconst compareCanonicalStrings = (left: string, right: string): number => left < right ? -1 : left > right ? 1 : 0;\n\nexport interface GenerateOptions { inputPath: string; outputDirectory: string; targets: string[]; check?: boolean; }\nexport interface GenerateResult { changed: string[]; stale: string[]; files: GeneratedFile[]; }\n\nexport async function generateFromManifest(options: GenerateOptions): Promise<GenerateResult> {\n\tconst input = JSON.parse(await readFile(options.inputPath, \"utf8\"));\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) throw new Error(\"Manifest input must be a JSON object.\");\n\tconst bundle = \"modules\" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };\n\tconst ir = compileManifestBundle(bundle);\n\tconst files = (await Promise.all(options.targets.map(async (name) => {\n\t\tconst target = GENERATOR_TARGETS[name];\n\t\tif (!target) throw new Error(`Unknown generator target \"${name}\".`);\n\t\treturn (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));\n\t}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));\n\tconst expected = new Set(files.map((file) => file.path));\n\tconst existing = await listFiles(options.outputDirectory);\n\tconst selectedPrefixes = options.targets.map((target) => `${target}/`);\n\tconst stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));\n\tif (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));\n\tconst changed: string[] = [];\n\tfor (const file of files) {\n\t\tconst target = path.join(options.outputDirectory, file.path);\n\t\tlet current: string | undefined;\n\t\ttry { current = await readFile(target, \"utf8\"); } catch { current = undefined; }\n\t\tif (current !== file.content) {\n\t\t\tchanged.push(file.path);\n\t\t\tif (!options.check) { await mkdir(path.dirname(target), { recursive: true }); await writeFile(target, file.content, \"utf8\"); }\n\t\t}\n\t}\n\tif (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(\", \")}`);\n\treturn { changed, stale, files };\n}\n\nasync function listFiles(directory: string, prefix = \"\"): Promise<string[]> {\n\tlet entries;\n\ttry { entries = await readdir(directory, { withFileTypes: true }); } catch { return []; }\n\tconst nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));\n\treturn nested.flat().sort();\n}\n"],"mappings":"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","names":["path"]}
|
|
1
|
+
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { access, mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { compileManifestBundle, runGenerator, type GeneratedFile, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport { capabilityGenerator } from \"@fabricorg/gen-capability\";\nimport { docsGenerator } from \"@fabricorg/gen-docs\";\nimport { eventsGenerator } from \"@fabricorg/gen-events\";\nimport { typesGenerator } from \"@fabricorg/gen-types\";\nimport { prismaGenerator } from \"@fabricorg/gen-prisma\";\nimport { graphqlGenerator } from \"@fabricorg/gen-graphql\";\nimport { sduiGenerator } from \"@fabricorg/gen-sdui\";\nimport { conformanceGenerator } from \"@fabricorg/gen-conformance\";\nimport {\n\tassertAssemblyLockfile,\n\tassertAssemblyRuntimeCompatible,\n\ttype AssemblyLockfile,\n\ttype AvailableCapability,\n} from \"@fabricorg/assembly\";\nimport {\n\tassertSduiReleaseIntegrity,\n\ttype SduiRelease,\n} from \"@fabricorg/sdui-release\";\n\nexport const GENERATOR_TARGETS: Record<string, GeneratorTarget> = {\n\ttypes: typesGenerator,\n\tevents: eventsGenerator,\n\tcapability: capabilityGenerator,\n\tdocs: docsGenerator,\n\tprisma: prismaGenerator,\n\tgraphql: graphqlGenerator,\n\tsdui: sduiGenerator,\n\tconformance: conformanceGenerator,\n};\nconst compareCanonicalStrings = (left: string, right: string): number => left < right ? -1 : left > right ? 1 : 0;\n\nexport interface GenerateOptions { inputPath: string; outputDirectory: string; targets: string[]; check?: boolean; }\nexport interface GenerateResult { changed: string[]; stale: string[]; files: GeneratedFile[]; }\nexport interface InitializeCapabilityOptions { directory: string; namespace: string; }\nexport interface InitializeCapabilityResult { created: string[]; }\nexport interface CheckApplicationOptions { configPath: string; }\nexport interface CheckApplicationResult {\n\tapplication: string;\n\tcapabilities: number;\n\treleases: number;\n\tassemblyDigest: string;\n}\n\nconst usage = [\n\t\"Usage:\",\n\t\" fabric-gen init capability <namespace> [--directory <path>]\",\n\t\" fabric-gen check-application [--config <path>]\",\n\t\" fabric-gen --input <manifest.json> --out <directory> [--targets <list>] [--check]\",\n].join(\"\\n\");\n\nexport class FabricGenUsageError extends Error {\n\toverride readonly name = \"FabricGenUsageError\";\n}\n\nexport function fabricGenCliExitCode(error: unknown): number {\n\treturn error instanceof FabricGenUsageError ? 2 : 1;\n}\n\nfunction flagValue(args: readonly string[], flag: string): string | undefined {\n\tconst index = args.indexOf(flag);\n\tif (index < 0) return undefined;\n\tconst value = args[index + 1];\n\tif (!value || value.startsWith(\"--\")) throw new FabricGenUsageError(usage);\n\treturn value;\n}\n\n/** Execute one CLI command and return its single human-readable result line. */\nexport async function runFabricGenCommand(args: readonly string[]): Promise<string> {\n\tif (args[0] === \"init\") {\n\t\tif (args[1] !== \"capability\" || !args[2] || args[2].startsWith(\"--\")) {\n\t\t\tthrow new FabricGenUsageError(usage);\n\t\t}\n\t\tconst namespace = args[2];\n\t\tconst directory = flagValue(args, \"--directory\") ?? namespace;\n\t\tconst result = await initializeCapability({ directory, namespace });\n\t\treturn `Initialized capability \"${namespace}\" with ${result.created.length} files.`;\n\t}\n\tif (args[0] === \"check-application\") {\n\t\tconst configPath = flagValue(args, \"--config\") ?? \"fabric.application.json\";\n\t\tconst result = await checkApplication({ configPath });\n\t\treturn `Checked \"${result.application}\": ${result.capabilities} capabilities, ${result.releases} releases.`;\n\t}\n\tconst inputPath = flagValue(args, \"--input\");\n\tconst outputDirectory = flagValue(args, \"--out\");\n\tif (!inputPath || !outputDirectory) throw new FabricGenUsageError(usage);\n\tconst result = await generateFromManifest({\n\t\tinputPath,\n\t\toutputDirectory,\n\t\ttargets: (flagValue(args, \"--targets\") ?? \"types,events,capability,docs\")\n\t\t\t.split(\",\")\n\t\t\t.filter(Boolean),\n\t\tcheck: args.includes(\"--check\"),\n\t});\n\treturn `${args.includes(\"--check\") ? \"Checked\" : \"Generated\"} ${result.files.length} files.`;\n}\n\ninterface ApplicationCheckConfig {\n\tformatVersion: 1;\n\tassembly: string;\n\truntimeCapabilities: string;\n\treleases: string[];\n}\n\nasync function readJson(file: string): Promise<unknown> {\n\treturn JSON.parse(await readFile(file, \"utf8\"));\n}\n\nfunction assertApplicationCheckConfig(value: unknown): asserts value is ApplicationCheckConfig {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Application check configuration must be a JSON object.\");\n\t}\n\tconst config = value as Record<string, unknown>;\n\tif (config.formatVersion !== 1) throw new Error(\"Application check configuration formatVersion must be 1.\");\n\tif (typeof config.assembly !== \"string\" || !config.assembly) {\n\t\tthrow new Error(\"Application check configuration assembly must be a file path.\");\n\t}\n\tif (typeof config.runtimeCapabilities !== \"string\" || !config.runtimeCapabilities) {\n\t\tthrow new Error(\"Application check configuration runtimeCapabilities must be a file path.\");\n\t}\n\tif (!Array.isArray(config.releases) || !config.releases.every((entry) => typeof entry === \"string\" && entry)) {\n\t\tthrow new Error(\"Application check configuration releases must be an array of file paths.\");\n\t}\n}\n\n/**\n * Verify an application's immutable composition inputs before deployment.\n * Every runtime capability must exactly match the approved lockfile, and every\n * promoted experience release must be intact and bound to that assembly.\n */\nexport async function checkApplication(\n\toptions: CheckApplicationOptions,\n): Promise<CheckApplicationResult> {\n\tconst configValue = await readJson(options.configPath);\n\tassertApplicationCheckConfig(configValue);\n\tconst base = path.dirname(options.configPath);\n\tconst resolve = (file: string): string => path.resolve(base, file);\n\tconst assembly = await readJson(resolve(configValue.assembly)) as AssemblyLockfile;\n\tassertAssemblyLockfile(assembly);\n\tconst runtimeCapabilities = await readJson(\n\t\tresolve(configValue.runtimeCapabilities),\n\t) as AvailableCapability[];\n\tif (!Array.isArray(runtimeCapabilities)) {\n\t\tthrow new Error(\"Runtime capabilities must be a JSON array.\");\n\t}\n\tassertAssemblyRuntimeCompatible(assembly, runtimeCapabilities);\n\tfor (const releasePath of configValue.releases) {\n\t\tconst release = await readJson(resolve(releasePath)) as SduiRelease;\n\t\ttry {\n\t\t\tassertSduiReleaseIntegrity(release);\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${releasePath}\" is invalid: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t\tif (release.assemblyDigest !== assembly.assemblyDigest) {\n\t\t\tthrow new Error(\n\t\t\t\t`Experience release \"${release.document.name}@${release.document.version}\" belongs to assembly \"${release.assemblyDigest}\", not \"${assembly.assemblyDigest}\".`,\n\t\t\t);\n\t\t}\n\t}\n\treturn {\n\t\tapplication: assembly.application,\n\t\tcapabilities: assembly.capabilities.length,\n\t\treleases: configValue.releases.length,\n\t\tassemblyDigest: assembly.assemblyDigest,\n\t};\n}\n\n/**\n * Create the smallest useful capability source tree. The manifest is accepted\n * by the compiler immediately, while leaving domain vocabulary to the adopter.\n */\nexport async function initializeCapability(\n\toptions: InitializeCapabilityOptions,\n): Promise<InitializeCapabilityResult> {\n\tif (!/^[a-z][a-z0-9-]*$/.test(options.namespace)) {\n\t\tthrow new Error(\"Capability namespace must use lowercase letters, numbers, and hyphens.\");\n\t}\n\tconst displayName = options.namespace\n\t\t.split(\"-\")\n\t\t.map((part, index) => index === 0\n\t\t\t? `${part.charAt(0).toUpperCase()}${part.slice(1)}`\n\t\t\t: part)\n\t\t.join(\" \");\n\tconst manifestPath = path.join(options.directory, \"fabric.manifest.json\");\n\tconst readmePath = path.join(options.directory, \"README.md\");\n\tfor (const file of [readmePath, manifestPath]) {\n\t\ttry {\n\t\t\tawait access(file);\n\t\t\tthrow new Error(`Refusing to overwrite existing file \"${file}\".`);\n\t\t} catch (error) {\n\t\t\tif (error instanceof Error && error.message.startsWith(\"Refusing to overwrite\")) throw error;\n\t\t\tif ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n\t\t}\n\t}\n\tconst manifest = {\n\t\tmanifestVersion: 2,\n\t\tnamespace: options.namespace,\n\t\tobjectTypes: [],\n\t\tsubjectTypes: [],\n\t\tidPrefixes: [],\n\t\tdependencies: [],\n\t\tpolicies: [],\n\t\teventTypes: [],\n\t\tactions: [],\n\t\tviews: [],\n\t\tstateMachines: [],\n\t\tcapability: {\n\t\t\tdisplayName,\n\t\t\tdescription: `Governed ${displayName.toLowerCase()} capability.`,\n\t\t\tstability: \"experimental\",\n\t\t},\n\t};\n\tconst readme = [\n\t\t`# ${displayName}`,\n\t\t\"\",\n\t\t\"Define domain objects, governed actions, events, and projections in `fabric.manifest.json`.\",\n\t\t\"\",\n\t\t\"```bash\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated\",\n\t\t\"fabric-gen --input fabric.manifest.json --out generated --check\",\n\t\t\"```\",\n\t\t\"\",\n\t].join(\"\\n\");\n\tawait mkdir(options.directory, { recursive: true });\n\tconst created: string[] = [];\n\ttry {\n\t\tfor (const [file, content] of [\n\t\t\t[readmePath, readme],\n\t\t\t[manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`],\n\t\t] as const) {\n\t\t\tawait writeFile(file, content, { encoding: \"utf8\", flag: \"wx\" });\n\t\t\tcreated.push(file);\n\t\t}\n\t} catch (error) {\n\t\tawait Promise.all(created.map((file) => rm(file, { force: true })));\n\t\tif ((error as NodeJS.ErrnoException).code === \"EEXIST\") {\n\t\t\tthrow new Error(\"Refusing to overwrite a file created during capability initialization.\");\n\t\t}\n\t\tthrow error;\n\t}\n\treturn { created };\n}\n\nexport async function generateFromManifest(options: GenerateOptions): Promise<GenerateResult> {\n\tconst input = JSON.parse(await readFile(options.inputPath, \"utf8\"));\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) throw new Error(\"Manifest input must be a JSON object.\");\n\tconst bundle = \"modules\" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };\n\tconst ir = compileManifestBundle(bundle);\n\tconst files = (await Promise.all(options.targets.map(async (name) => {\n\t\tconst target = GENERATOR_TARGETS[name];\n\t\tif (!target) throw new Error(`Unknown generator target \"${name}\".`);\n\t\treturn (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));\n\t}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));\n\tconst expected = new Set(files.map((file) => file.path));\n\tconst existing = await listFiles(options.outputDirectory);\n\tconst selectedPrefixes = options.targets.map((target) => `${target}/`);\n\tconst stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));\n\tif (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));\n\tconst changed: string[] = [];\n\tfor (const file of files) {\n\t\tconst target = path.join(options.outputDirectory, file.path);\n\t\tlet current: string | undefined;\n\t\ttry { current = await readFile(target, \"utf8\"); } catch { current = undefined; }\n\t\tif (current !== file.content) {\n\t\t\tchanged.push(file.path);\n\t\t\tif (!options.check) { await mkdir(path.dirname(target), { recursive: true }); await writeFile(target, file.content, \"utf8\"); }\n\t\t}\n\t}\n\tif (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(\", \")}`);\n\treturn { changed, stale, files };\n}\n\nasync function listFiles(directory: string, prefix = \"\"): Promise<string[]> {\n\tlet entries;\n\ttry { entries = await readdir(directory, { withFileTypes: true }); } catch { return []; }\n\tconst nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));\n\treturn nested.flat().sort();\n}\n"],"mappings":"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","names":["result","path"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -12,6 +12,39 @@ interface GenerateResult {
|
|
|
12
12
|
stale: string[];
|
|
13
13
|
files: GeneratedFile[];
|
|
14
14
|
}
|
|
15
|
+
interface InitializeCapabilityOptions {
|
|
16
|
+
directory: string;
|
|
17
|
+
namespace: string;
|
|
18
|
+
}
|
|
19
|
+
interface InitializeCapabilityResult {
|
|
20
|
+
created: string[];
|
|
21
|
+
}
|
|
22
|
+
interface CheckApplicationOptions {
|
|
23
|
+
configPath: string;
|
|
24
|
+
}
|
|
25
|
+
interface CheckApplicationResult {
|
|
26
|
+
application: string;
|
|
27
|
+
capabilities: number;
|
|
28
|
+
releases: number;
|
|
29
|
+
assemblyDigest: string;
|
|
30
|
+
}
|
|
31
|
+
declare class FabricGenUsageError extends Error {
|
|
32
|
+
readonly name = "FabricGenUsageError";
|
|
33
|
+
}
|
|
34
|
+
declare function fabricGenCliExitCode(error: unknown): number;
|
|
35
|
+
/** Execute one CLI command and return its single human-readable result line. */
|
|
36
|
+
declare function runFabricGenCommand(args: readonly string[]): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Verify an application's immutable composition inputs before deployment.
|
|
39
|
+
* Every runtime capability must exactly match the approved lockfile, and every
|
|
40
|
+
* promoted experience release must be intact and bound to that assembly.
|
|
41
|
+
*/
|
|
42
|
+
declare function checkApplication(options: CheckApplicationOptions): Promise<CheckApplicationResult>;
|
|
43
|
+
/**
|
|
44
|
+
* Create the smallest useful capability source tree. The manifest is accepted
|
|
45
|
+
* by the compiler immediately, while leaving domain vocabulary to the adopter.
|
|
46
|
+
*/
|
|
47
|
+
declare function initializeCapability(options: InitializeCapabilityOptions): Promise<InitializeCapabilityResult>;
|
|
15
48
|
declare function generateFromManifest(options: GenerateOptions): Promise<GenerateResult>;
|
|
16
49
|
|
|
17
|
-
export { GENERATOR_TARGETS, type GenerateOptions, type GenerateResult, generateFromManifest };
|
|
50
|
+
export { type CheckApplicationOptions, type CheckApplicationResult, FabricGenUsageError, GENERATOR_TARGETS, type GenerateOptions, type GenerateResult, type InitializeCapabilityOptions, type InitializeCapabilityResult, checkApplication, fabricGenCliExitCode, generateFromManifest, initializeCapability, runFabricGenCommand };
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,39 @@ interface GenerateResult {
|
|
|
12
12
|
stale: string[];
|
|
13
13
|
files: GeneratedFile[];
|
|
14
14
|
}
|
|
15
|
+
interface InitializeCapabilityOptions {
|
|
16
|
+
directory: string;
|
|
17
|
+
namespace: string;
|
|
18
|
+
}
|
|
19
|
+
interface InitializeCapabilityResult {
|
|
20
|
+
created: string[];
|
|
21
|
+
}
|
|
22
|
+
interface CheckApplicationOptions {
|
|
23
|
+
configPath: string;
|
|
24
|
+
}
|
|
25
|
+
interface CheckApplicationResult {
|
|
26
|
+
application: string;
|
|
27
|
+
capabilities: number;
|
|
28
|
+
releases: number;
|
|
29
|
+
assemblyDigest: string;
|
|
30
|
+
}
|
|
31
|
+
declare class FabricGenUsageError extends Error {
|
|
32
|
+
readonly name = "FabricGenUsageError";
|
|
33
|
+
}
|
|
34
|
+
declare function fabricGenCliExitCode(error: unknown): number;
|
|
35
|
+
/** Execute one CLI command and return its single human-readable result line. */
|
|
36
|
+
declare function runFabricGenCommand(args: readonly string[]): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Verify an application's immutable composition inputs before deployment.
|
|
39
|
+
* Every runtime capability must exactly match the approved lockfile, and every
|
|
40
|
+
* promoted experience release must be intact and bound to that assembly.
|
|
41
|
+
*/
|
|
42
|
+
declare function checkApplication(options: CheckApplicationOptions): Promise<CheckApplicationResult>;
|
|
43
|
+
/**
|
|
44
|
+
* Create the smallest useful capability source tree. The manifest is accepted
|
|
45
|
+
* by the compiler immediately, while leaving domain vocabulary to the adopter.
|
|
46
|
+
*/
|
|
47
|
+
declare function initializeCapability(options: InitializeCapabilityOptions): Promise<InitializeCapabilityResult>;
|
|
15
48
|
declare function generateFromManifest(options: GenerateOptions): Promise<GenerateResult>;
|
|
16
49
|
|
|
17
|
-
export { GENERATOR_TARGETS, type GenerateOptions, type GenerateResult, generateFromManifest };
|
|
50
|
+
export { type CheckApplicationOptions, type CheckApplicationResult, FabricGenUsageError, GENERATOR_TARGETS, type GenerateOptions, type GenerateResult, type InitializeCapabilityOptions, type InitializeCapabilityResult, checkApplication, fabricGenCliExitCode, generateFromManifest, initializeCapability, runFabricGenCommand };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
|
+
FabricGenUsageError,
|
|
2
3
|
GENERATOR_TARGETS,
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
checkApplication,
|
|
5
|
+
fabricGenCliExitCode,
|
|
6
|
+
generateFromManifest,
|
|
7
|
+
initializeCapability,
|
|
8
|
+
runFabricGenCommand
|
|
9
|
+
} from "./chunk-CUNWMAA2.js";
|
|
5
10
|
export {
|
|
11
|
+
FabricGenUsageError,
|
|
6
12
|
GENERATOR_TARGETS,
|
|
7
|
-
|
|
13
|
+
checkApplication,
|
|
14
|
+
fabricGenCliExitCode,
|
|
15
|
+
generateFromManifest,
|
|
16
|
+
initializeCapability,
|
|
17
|
+
runFabricGenCommand
|
|
8
18
|
};
|
|
9
19
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabricorg/fabric-gen",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"description": "Fabric capability scaffolding, deterministic generation, and application composition checks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.cjs",
|
|
@@ -27,22 +27,24 @@
|
|
|
27
27
|
"CHANGELOG.md"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@fabricorg/
|
|
31
|
-
"@fabricorg/
|
|
32
|
-
"@fabricorg/gen-
|
|
33
|
-
"@fabricorg/gen-
|
|
34
|
-
"@fabricorg/gen-
|
|
35
|
-
"@fabricorg/gen-
|
|
36
|
-
"@fabricorg/gen-
|
|
37
|
-
"@fabricorg/
|
|
38
|
-
"@fabricorg/gen-
|
|
30
|
+
"@fabricorg/assembly": "^0.3.0",
|
|
31
|
+
"@fabricorg/compiler": "^2.2.0",
|
|
32
|
+
"@fabricorg/gen-capability": "^0.5.0",
|
|
33
|
+
"@fabricorg/gen-events": "^0.2.4",
|
|
34
|
+
"@fabricorg/gen-graphql": "^3.1.0",
|
|
35
|
+
"@fabricorg/gen-sdui": "^0.5.1",
|
|
36
|
+
"@fabricorg/gen-types": "^2.0.1",
|
|
37
|
+
"@fabricorg/sdui-release": "^0.3.0",
|
|
38
|
+
"@fabricorg/gen-prisma": "^2.0.1",
|
|
39
|
+
"@fabricorg/gen-docs": "^0.2.4",
|
|
40
|
+
"@fabricorg/gen-conformance": "^0.3.0"
|
|
39
41
|
},
|
|
40
42
|
"devDependencies": {
|
|
41
43
|
"@types/node": "^22.10.0",
|
|
42
44
|
"tsup": "^8.5.0",
|
|
43
45
|
"typescript": "^5.7.3",
|
|
44
46
|
"vitest": "^4.1.5",
|
|
45
|
-
"@fabricorg/platform": "^1.
|
|
47
|
+
"@fabricorg/platform": "^1.2.0"
|
|
46
48
|
},
|
|
47
49
|
"engines": {
|
|
48
50
|
"node": ">=20"
|
package/dist/chunk-QOD7G4YK.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
// index.ts
|
|
2
|
-
import { mkdir, readFile, readdir, rm, writeFile } from "fs/promises";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { compileManifestBundle, runGenerator } from "@fabricorg/compiler";
|
|
5
|
-
import { capabilityGenerator } from "@fabricorg/gen-capability";
|
|
6
|
-
import { docsGenerator } from "@fabricorg/gen-docs";
|
|
7
|
-
import { eventsGenerator } from "@fabricorg/gen-events";
|
|
8
|
-
import { typesGenerator } from "@fabricorg/gen-types";
|
|
9
|
-
import { prismaGenerator } from "@fabricorg/gen-prisma";
|
|
10
|
-
import { graphqlGenerator } from "@fabricorg/gen-graphql";
|
|
11
|
-
import { sduiGenerator } from "@fabricorg/gen-sdui";
|
|
12
|
-
import { conformanceGenerator } from "@fabricorg/gen-conformance";
|
|
13
|
-
var GENERATOR_TARGETS = {
|
|
14
|
-
types: typesGenerator,
|
|
15
|
-
events: eventsGenerator,
|
|
16
|
-
capability: capabilityGenerator,
|
|
17
|
-
docs: docsGenerator,
|
|
18
|
-
prisma: prismaGenerator,
|
|
19
|
-
graphql: graphqlGenerator,
|
|
20
|
-
sdui: sduiGenerator,
|
|
21
|
-
conformance: conformanceGenerator
|
|
22
|
-
};
|
|
23
|
-
var compareCanonicalStrings = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
24
|
-
async function generateFromManifest(options) {
|
|
25
|
-
const input = JSON.parse(await readFile(options.inputPath, "utf8"));
|
|
26
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("Manifest input must be a JSON object.");
|
|
27
|
-
const bundle = "modules" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };
|
|
28
|
-
const ir = compileManifestBundle(bundle);
|
|
29
|
-
const files = (await Promise.all(options.targets.map(async (name) => {
|
|
30
|
-
const target = GENERATOR_TARGETS[name];
|
|
31
|
-
if (!target) throw new Error(`Unknown generator target "${name}".`);
|
|
32
|
-
return (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));
|
|
33
|
-
}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));
|
|
34
|
-
const expected = new Set(files.map((file) => file.path));
|
|
35
|
-
const existing = await listFiles(options.outputDirectory);
|
|
36
|
-
const selectedPrefixes = options.targets.map((target) => `${target}/`);
|
|
37
|
-
const stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));
|
|
38
|
-
if (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));
|
|
39
|
-
const changed = [];
|
|
40
|
-
for (const file of files) {
|
|
41
|
-
const target = path.join(options.outputDirectory, file.path);
|
|
42
|
-
let current;
|
|
43
|
-
try {
|
|
44
|
-
current = await readFile(target, "utf8");
|
|
45
|
-
} catch {
|
|
46
|
-
current = void 0;
|
|
47
|
-
}
|
|
48
|
-
if (current !== file.content) {
|
|
49
|
-
changed.push(file.path);
|
|
50
|
-
if (!options.check) {
|
|
51
|
-
await mkdir(path.dirname(target), { recursive: true });
|
|
52
|
-
await writeFile(target, file.content, "utf8");
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
if (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(", ")}`);
|
|
57
|
-
return { changed, stale, files };
|
|
58
|
-
}
|
|
59
|
-
async function listFiles(directory, prefix = "") {
|
|
60
|
-
let entries;
|
|
61
|
-
try {
|
|
62
|
-
entries = await readdir(directory, { withFileTypes: true });
|
|
63
|
-
} catch {
|
|
64
|
-
return [];
|
|
65
|
-
}
|
|
66
|
-
const nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));
|
|
67
|
-
return nested.flat().sort();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export {
|
|
71
|
-
GENERATOR_TARGETS,
|
|
72
|
-
generateFromManifest
|
|
73
|
-
};
|
|
74
|
-
//# sourceMappingURL=chunk-QOD7G4YK.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../index.ts"],"sourcesContent":["import { mkdir, readFile, readdir, rm, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { compileManifestBundle, runGenerator, type GeneratedFile, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport { capabilityGenerator } from \"@fabricorg/gen-capability\";\nimport { docsGenerator } from \"@fabricorg/gen-docs\";\nimport { eventsGenerator } from \"@fabricorg/gen-events\";\nimport { typesGenerator } from \"@fabricorg/gen-types\";\nimport { prismaGenerator } from \"@fabricorg/gen-prisma\";\nimport { graphqlGenerator } from \"@fabricorg/gen-graphql\";\nimport { sduiGenerator } from \"@fabricorg/gen-sdui\";\nimport { conformanceGenerator } from \"@fabricorg/gen-conformance\";\n\nexport const GENERATOR_TARGETS: Record<string, GeneratorTarget> = {\n\ttypes: typesGenerator,\n\tevents: eventsGenerator,\n\tcapability: capabilityGenerator,\n\tdocs: docsGenerator,\n\tprisma: prismaGenerator,\n\tgraphql: graphqlGenerator,\n\tsdui: sduiGenerator,\n\tconformance: conformanceGenerator,\n};\nconst compareCanonicalStrings = (left: string, right: string): number => left < right ? -1 : left > right ? 1 : 0;\n\nexport interface GenerateOptions { inputPath: string; outputDirectory: string; targets: string[]; check?: boolean; }\nexport interface GenerateResult { changed: string[]; stale: string[]; files: GeneratedFile[]; }\n\nexport async function generateFromManifest(options: GenerateOptions): Promise<GenerateResult> {\n\tconst input = JSON.parse(await readFile(options.inputPath, \"utf8\"));\n\tif (!input || typeof input !== \"object\" || Array.isArray(input)) throw new Error(\"Manifest input must be a JSON object.\");\n\tconst bundle = \"modules\" in input ? input : { manifestVersion: input.manifestVersion, modules: [input] };\n\tconst ir = compileManifestBundle(bundle);\n\tconst files = (await Promise.all(options.targets.map(async (name) => {\n\t\tconst target = GENERATOR_TARGETS[name];\n\t\tif (!target) throw new Error(`Unknown generator target \"${name}\".`);\n\t\treturn (await runGenerator(target, ir)).map((file) => ({ ...file, path: `${name}/${file.path}` }));\n\t}))).flat().sort((left, right) => compareCanonicalStrings(left.path, right.path));\n\tconst expected = new Set(files.map((file) => file.path));\n\tconst existing = await listFiles(options.outputDirectory);\n\tconst selectedPrefixes = options.targets.map((target) => `${target}/`);\n\tconst stale = existing.filter((file) => selectedPrefixes.some((prefix) => file.startsWith(prefix)) && !expected.has(file));\n\tif (!options.check) await Promise.all(stale.map((file) => rm(path.join(options.outputDirectory, file), { force: true })));\n\tconst changed: string[] = [];\n\tfor (const file of files) {\n\t\tconst target = path.join(options.outputDirectory, file.path);\n\t\tlet current: string | undefined;\n\t\ttry { current = await readFile(target, \"utf8\"); } catch { current = undefined; }\n\t\tif (current !== file.content) {\n\t\t\tchanged.push(file.path);\n\t\t\tif (!options.check) { await mkdir(path.dirname(target), { recursive: true }); await writeFile(target, file.content, \"utf8\"); }\n\t\t}\n\t}\n\tif (options.check && (changed.length || stale.length)) throw new Error(`Generated artifacts drifted: ${[...changed, ...stale.map((file) => `stale:${file}`)].join(\", \")}`);\n\treturn { changed, stale, files };\n}\n\nasync function listFiles(directory: string, prefix = \"\"): Promise<string[]> {\n\tlet entries;\n\ttry { entries = await readdir(directory, { withFileTypes: true }); } catch { return []; }\n\tconst nested = await Promise.all(entries.map((entry) => entry.isDirectory() ? listFiles(path.join(directory, entry.name), `${prefix}${entry.name}/`) : [`${prefix}${entry.name}`]));\n\treturn nested.flat().sort();\n}\n"],"mappings":"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","names":[]}
|