@clearlydev/nx-archweave 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/bin/review-verdict.js +5 -248
  2. package/dist/eslint/index.js +28 -321
  3. package/dist/generators/_chunks/chunk-2WSX5YNB.js +274 -0
  4. package/dist/generators/_chunks/chunk-34V6HAJT.js +55 -0
  5. package/dist/generators/_chunks/chunk-3A6RZUCZ.js +114 -0
  6. package/dist/generators/_chunks/chunk-47T7NOPP.js +30 -0
  7. package/dist/generators/_chunks/chunk-5MI3O4VZ.js +99 -0
  8. package/dist/generators/_chunks/chunk-67INEVWL.js +1068 -0
  9. package/dist/generators/_chunks/chunk-6ZTIUBB2.js +139 -0
  10. package/dist/generators/_chunks/chunk-AIJCJ7JK.js +203 -0
  11. package/dist/generators/_chunks/chunk-AQHV7DJS.js +656 -0
  12. package/dist/generators/_chunks/chunk-C2VVUWBA.js +386 -0
  13. package/dist/generators/_chunks/chunk-EXYZLL7A.js +234 -0
  14. package/dist/generators/_chunks/chunk-FQHFT5IH.js +50 -0
  15. package/dist/generators/_chunks/chunk-H222FPLK.js +80 -0
  16. package/dist/generators/_chunks/chunk-IIDOBI42.js +616 -0
  17. package/dist/generators/_chunks/chunk-JHRTVURZ.js +189 -0
  18. package/dist/generators/_chunks/chunk-L2RZ2LBO.js +132 -0
  19. package/dist/generators/_chunks/chunk-MQNQJOWA.js +217 -0
  20. package/dist/generators/_chunks/chunk-QQNDYJTR.js +243 -0
  21. package/dist/generators/_chunks/chunk-SFXU6IUS.js +0 -0
  22. package/dist/generators/_chunks/chunk-SNBIVIMI.js +89 -0
  23. package/dist/generators/_chunks/chunk-TUN34LAQ.js +8 -0
  24. package/dist/generators/_chunks/chunk-TXAQ2GJC.js +20 -0
  25. package/dist/generators/_chunks/chunk-U6LAFHSF.js +49 -0
  26. package/dist/generators/_chunks/chunk-URV6FLUH.js +73 -0
  27. package/dist/generators/_chunks/chunk-YNMLB4DL.js +25 -0
  28. package/dist/generators/_chunks/chunk-YY2UESLM.js +282 -0
  29. package/dist/generators/add-agent-rules/generator.js +11 -842
  30. package/dist/generators/add-backend/generator.js +11 -906
  31. package/dist/generators/add-fsd-lite/generator.js +12 -801
  32. package/dist/generators/add-github-templates/generator.js +13 -116
  33. package/dist/generators/add-integration/generator.js +15 -743
  34. package/dist/generators/add-review/generator.js +12 -1231
  35. package/dist/generators/allow-builds/generator.js +7 -71
  36. package/dist/generators/doctor/generator.js +74 -2042
  37. package/dist/generators/entity/generator.js +15 -604
  38. package/dist/generators/feature/generator.js +15 -604
  39. package/dist/generators/init/generator.js +68 -3376
  40. package/dist/generators/install-integration/generator.js +35 -871
  41. package/dist/generators/page/generator.js +15 -604
  42. package/dist/generators/record-integration/generator.js +12 -778
  43. package/dist/generators/shared/generator.js +15 -604
  44. package/dist/generators/widget/generator.js +15 -604
  45. package/dist/index.js +5 -663
  46. package/package.json +1 -1
@@ -0,0 +1,243 @@
1
+ import {
2
+ DEFAULT_BOUNDARY_TAGS
3
+ } from "./chunk-6ZTIUBB2.js";
4
+
5
+ // ../templates/dist/backend/shared-types.js
6
+ function sharedTypesIndexContent() {
7
+ return `export * from './lib/api-types.js';
8
+ `;
9
+ }
10
+ function sharedTypesApiTypesContent() {
11
+ return [
12
+ "// Types shared between the frontend and the backend live here.",
13
+ "// Example: the api app returns this from GET /api/health, and the",
14
+ "// frontend consumes the same shape \u2014 one definition, no drift.",
15
+ "export interface ApiHealthResponse {",
16
+ " status: 'ok';",
17
+ "}",
18
+ ""
19
+ ].join("\n");
20
+ }
21
+ function sharedTypesPackageJsonContent(packageName, sharedTag = "scope:shared") {
22
+ return `${JSON.stringify({
23
+ name: packageName,
24
+ version: "0.0.1",
25
+ private: true,
26
+ type: "module",
27
+ main: "./src/index.ts",
28
+ types: "./src/index.ts",
29
+ exports: {
30
+ ".": {
31
+ types: "./src/index.ts",
32
+ import: "./src/index.ts",
33
+ default: "./src/index.ts"
34
+ }
35
+ },
36
+ nx: {
37
+ projectType: "library",
38
+ tags: [sharedTag],
39
+ targets: {}
40
+ }
41
+ }, null, 2)}
42
+ `;
43
+ }
44
+
45
+ // ../template-engine/dist/backend/compose-backend-wiring.js
46
+ var DEFAULT_SHARED_TYPES_ROOT = "libs/shared-types";
47
+ function readSharedTypesConfig(config) {
48
+ const value = config?.["sharedTypes"];
49
+ if (value === false)
50
+ return false;
51
+ if (typeof value !== "object" || value === null)
52
+ return { path: DEFAULT_SHARED_TYPES_ROOT };
53
+ const record = value;
54
+ const path = typeof record["path"] === "string" && record["path"].trim() !== "" ? record["path"].replace(/\/+$/, "") : DEFAULT_SHARED_TYPES_ROOT;
55
+ const importPath = typeof record["importPath"] === "string" && record["importPath"].trim() !== "" ? record["importPath"] : void 0;
56
+ return importPath === void 0 ? { path } : { path, importPath };
57
+ }
58
+ function composeBackendWiring(input) {
59
+ const scoped = /^@([^/]+)\//.exec(input.workspaceName);
60
+ const scope = scoped ? `@${scoped[1]}` : `@${input.workspaceName.split("/").pop() || "workspace"}`;
61
+ const sharedTypesRoot = input.sharedTypes?.path ?? DEFAULT_SHARED_TYPES_ROOT;
62
+ const sharedTypesPackageName = input.sharedTypes?.importPath ?? `${scope}/shared-types`;
63
+ const tagByRole = input.tags ?? DEFAULT_BOUNDARY_TAGS;
64
+ return {
65
+ sharedTypesFiles: [
66
+ { filePath: `${sharedTypesRoot}/package.json`, content: sharedTypesPackageJsonContent(sharedTypesPackageName, tagByRole.shared) },
67
+ { filePath: `${sharedTypesRoot}/src/index.ts`, content: sharedTypesIndexContent() },
68
+ { filePath: `${sharedTypesRoot}/src/lib/api-types.ts`, content: sharedTypesApiTypesContent() }
69
+ ],
70
+ sharedTypesPackageName,
71
+ sharedTypesRoot,
72
+ tagByRole
73
+ };
74
+ }
75
+ function addSharedTypesNpmWorkspace(packageJsonText, entry = DEFAULT_SHARED_TYPES_ROOT) {
76
+ let parsed;
77
+ try {
78
+ parsed = JSON.parse(packageJsonText);
79
+ } catch {
80
+ return { status: "unrecognized" };
81
+ }
82
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
83
+ return { status: "unrecognized" };
84
+ const pkg = parsed;
85
+ const field = pkg["workspaces"];
86
+ let target;
87
+ if (field === void 0) {
88
+ target = [];
89
+ } else if (Array.isArray(field)) {
90
+ target = field;
91
+ } else if (field !== null && typeof field === "object" && Array.isArray(field.packages)) {
92
+ target = field.packages;
93
+ } else {
94
+ return { status: "unrecognized" };
95
+ }
96
+ const parentGlob = `${entry.split("/").slice(0, -1).join("/")}/*`;
97
+ if (target.some((existing) => existing === entry || existing === parentGlob))
98
+ return { status: "present" };
99
+ const surgical = insertSharedTypesWorkspace(packageJsonText, field === void 0 ? "absent" : Array.isArray(field) ? "array" : "object", JSON.stringify(entry));
100
+ if (surgical !== null)
101
+ return { status: "added", text: surgical };
102
+ if (field === void 0)
103
+ pkg["workspaces"] = target;
104
+ target.push(entry);
105
+ const indent = /\n([ \t]+)"/.exec(packageJsonText)?.[1] ?? " ";
106
+ const trailing = packageJsonText.endsWith("\n") ? "\n" : "";
107
+ return { status: "added", text: `${JSON.stringify(pkg, null, indent)}${trailing}` };
108
+ }
109
+ function skipJsonValue(text, start) {
110
+ if (text[start] === '"') {
111
+ let i = start + 1;
112
+ while (i < text.length && text[i] !== '"')
113
+ i += text[i] === "\\" ? 2 : 1;
114
+ return i + 1;
115
+ }
116
+ if (text[start] === "[" || text[start] === "{") {
117
+ let depth = 0;
118
+ let i = start;
119
+ while (i < text.length) {
120
+ const c = text[i];
121
+ if (c === '"') {
122
+ i = skipJsonValue(text, i);
123
+ continue;
124
+ }
125
+ if (c === "[" || c === "{")
126
+ depth++;
127
+ if (c === "]" || c === "}") {
128
+ depth--;
129
+ if (depth === 0)
130
+ return i + 1;
131
+ }
132
+ i++;
133
+ }
134
+ return -1;
135
+ }
136
+ const literal = /^[^,}\]\s]+/.exec(text.slice(start));
137
+ return literal ? start + literal[0].length : -1;
138
+ }
139
+ function objectMembers(text, open) {
140
+ const members = [];
141
+ let i = open + 1;
142
+ for (; ; ) {
143
+ while (/[\s,]/.test(text[i] ?? ""))
144
+ i++;
145
+ if (text[i] === "}")
146
+ return members;
147
+ if (text[i] !== '"')
148
+ return null;
149
+ const keyEnd = skipJsonValue(text, i);
150
+ const key = JSON.parse(text.slice(i, keyEnd));
151
+ i = keyEnd;
152
+ while (/\s/.test(text[i] ?? ""))
153
+ i++;
154
+ if (text[i] !== ":")
155
+ return null;
156
+ i++;
157
+ while (/\s/.test(text[i] ?? ""))
158
+ i++;
159
+ const valueEnd = skipJsonValue(text, i);
160
+ if (valueEnd === -1)
161
+ return null;
162
+ members.push({ key, valueStart: i, valueEnd });
163
+ i = valueEnd;
164
+ }
165
+ }
166
+ function appendToArray(text, open, close, eol, quoted) {
167
+ const inner = text.slice(open + 1, close - 1);
168
+ if (inner.trim() === "")
169
+ return `${text.slice(0, open + 1)}${quoted}${text.slice(close - 1)}`;
170
+ if (!inner.includes("\n")) {
171
+ const body = inner.replace(/\s+$/, "");
172
+ return `${text.slice(0, open + 1)}${body}, ${quoted}${inner.slice(body.length)}${text.slice(close - 1)}`;
173
+ }
174
+ const lastEntryLineStart = text.lastIndexOf("\n", open + 1 + inner.trimEnd().length - 1) + 1;
175
+ const itemIndent = /^[ \t]*/.exec(text.slice(lastEntryLineStart))?.[0] ?? " ";
176
+ const bodyEnd = open + 1 + inner.trimEnd().length;
177
+ return `${text.slice(0, bodyEnd)},${eol}${itemIndent}${quoted}${text.slice(bodyEnd)}`;
178
+ }
179
+ function insertSharedTypesWorkspace(text, form, quoted) {
180
+ const eol = text.includes("\r\n") ? "\r\n" : "\n";
181
+ const rootOpen = text.indexOf("{");
182
+ if (rootOpen === -1)
183
+ return null;
184
+ const members = objectMembers(text, rootOpen);
185
+ if (members === null)
186
+ return null;
187
+ const workspaces = members.find((member) => member.key === "workspaces");
188
+ if (form === "absent") {
189
+ const last = members[members.length - 1];
190
+ const indent = /\n([ \t]+)"/.exec(text)?.[1] ?? " ";
191
+ if (last === void 0) {
192
+ const close = skipJsonValue(text, rootOpen) - 1;
193
+ return `${text.slice(0, rootOpen + 1)}${eol}${indent}"workspaces": [${quoted}]${eol}${text.slice(close)}`;
194
+ }
195
+ return `${text.slice(0, last.valueEnd)},${eol}${indent}"workspaces": [${quoted}]${text.slice(last.valueEnd)}`;
196
+ }
197
+ if (workspaces === void 0)
198
+ return null;
199
+ if (form === "array") {
200
+ if (text[workspaces.valueStart] !== "[")
201
+ return null;
202
+ return appendToArray(text, workspaces.valueStart, workspaces.valueEnd, eol, quoted);
203
+ }
204
+ if (text[workspaces.valueStart] !== "{")
205
+ return null;
206
+ const packages = objectMembers(text, workspaces.valueStart)?.find((member) => member.key === "packages");
207
+ if (packages === void 0 || text[packages.valueStart] !== "[")
208
+ return null;
209
+ return appendToArray(text, packages.valueStart, packages.valueEnd, eol, quoted);
210
+ }
211
+ function addSharedTypesWorkspaceGlob(yamlText, entry = DEFAULT_SHARED_TYPES_ROOT) {
212
+ const escape = (value) => value.replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
213
+ const parentGlob = `${entry.split("/").slice(0, -1).join("/")}/*`;
214
+ if (new RegExp(`^\\s*-\\s*['"]?(${escape(entry)}|${escape(parentGlob)})['"]?\\s*$`, "m").test(yamlText)) {
215
+ return { status: "present" };
216
+ }
217
+ const lines = yamlText.split("\n");
218
+ const packagesIndex = lines.findIndex((line) => /^packages:\s*$/.test(line));
219
+ if (packagesIndex === -1)
220
+ return { status: "unrecognized" };
221
+ let lastEntry = packagesIndex;
222
+ for (let i = packagesIndex + 1; i < lines.length; i++) {
223
+ if (/^\s+-\s+\S/.test(lines[i])) {
224
+ lastEntry = i;
225
+ } else if (lines[i].trim() === "") {
226
+ continue;
227
+ } else {
228
+ break;
229
+ }
230
+ }
231
+ if (lastEntry === packagesIndex)
232
+ return { status: "unrecognized" };
233
+ const indent = /^(\s+)-/.exec(lines[lastEntry])?.[1] ?? " ";
234
+ lines.splice(lastEntry + 1, 0, `${indent}- '${entry}'`);
235
+ return { status: "added", text: lines.join("\n") };
236
+ }
237
+
238
+ export {
239
+ readSharedTypesConfig,
240
+ composeBackendWiring,
241
+ addSharedTypesNpmWorkspace,
242
+ addSharedTypesWorkspaceGlob
243
+ };
File without changes
@@ -0,0 +1,89 @@
1
+ import {
2
+ generatorFilesDir,
3
+ renderTemplateFiles
4
+ } from "./chunk-YNMLB4DL.js";
5
+ import {
6
+ resolveDryRun
7
+ } from "./chunk-TUN34LAQ.js";
8
+ import {
9
+ readToolkitConfig,
10
+ resolveLocaleOption
11
+ } from "./chunk-EXYZLL7A.js";
12
+
13
+ // src/generators/add-github-templates/generator.ts
14
+ import { join } from "node:path";
15
+
16
+ // src/generators/add-github-templates/render.ts
17
+ var ACTION_LINES = {
18
+ created: "created",
19
+ unchanged: "unchanged (already matches the generated version)",
20
+ skipped: "left as-is (a different file already exists there \u2014 never overwritten)"
21
+ };
22
+ function renderAddGithubTemplatesReport(report) {
23
+ const lines = [];
24
+ if (report.files.length === 0) {
25
+ lines.push("add-github-templates: nothing selected (issue/pr/codeowners all false) \u2014 no files to install.");
26
+ return lines.join("\n");
27
+ }
28
+ if (report.dryRun) {
29
+ lines.push("add-github-templates dry-run \u2014 no files were written.");
30
+ lines.push("");
31
+ for (const file of report.files) {
32
+ lines.push(`${file.filePath}:`);
33
+ lines.push(file.content);
34
+ lines.push("");
35
+ }
36
+ lines.push("Effective decision:");
37
+ }
38
+ for (const file of report.files) {
39
+ lines.push(` ${file.filePath}: ${ACTION_LINES[file.action]}`);
40
+ }
41
+ return lines.join("\n");
42
+ }
43
+
44
+ // src/generators/add-github-templates/generator.ts
45
+ var BUG_REPORT_PATH = ".github/ISSUE_TEMPLATE/bug-report.yml";
46
+ var FEATURE_REQUEST_PATH = ".github/ISSUE_TEMPLATE/feature-request.yml";
47
+ var PULL_REQUEST_TEMPLATE_PATH = ".github/PULL_REQUEST_TEMPLATE.md";
48
+ var CODEOWNERS_PATH = ".github/CODEOWNERS";
49
+ function composeGithubTemplates(groups, locale) {
50
+ const files = generatorFilesDir("add-github-templates", import.meta.url);
51
+ return ["issue", "pr", "codeowners"].filter((group) => groups[group]).flatMap((group) => renderTemplateFiles(join(files, locale, group), ".", {}));
52
+ }
53
+ function runAddGithubTemplates(tree, options) {
54
+ const locale = resolveLocaleOption(options.locale, readToolkitConfig(tree));
55
+ const plan = composeGithubTemplates(
56
+ { issue: options.issue ?? false, pr: options.pr ?? true, codeowners: options.codeowners ?? false },
57
+ locale
58
+ );
59
+ const dryRun = options.dryRun ?? false;
60
+ const files = plan.map(({ filePath, content }) => {
61
+ const existing = tree.read(filePath, "utf-8");
62
+ let action;
63
+ if (existing === null) {
64
+ action = "created";
65
+ if (!dryRun) tree.write(filePath, content);
66
+ } else if (existing === content) {
67
+ action = "unchanged";
68
+ } else {
69
+ action = "skipped";
70
+ }
71
+ return { filePath, action, content };
72
+ });
73
+ return { dryRun, files };
74
+ }
75
+ async function addGithubTemplatesGenerator(tree, options) {
76
+ console.log(renderAddGithubTemplatesReport(runAddGithubTemplates(tree, { ...options, dryRun: resolveDryRun(options) })));
77
+ }
78
+ var generator_default = addGithubTemplatesGenerator;
79
+
80
+ export {
81
+ renderAddGithubTemplatesReport,
82
+ BUG_REPORT_PATH,
83
+ FEATURE_REQUEST_PATH,
84
+ PULL_REQUEST_TEMPLATE_PATH,
85
+ CODEOWNERS_PATH,
86
+ runAddGithubTemplates,
87
+ addGithubTemplatesGenerator,
88
+ generator_default
89
+ };
@@ -0,0 +1,8 @@
1
+ // src/generators/shared/dry-run.ts
2
+ function resolveDryRun(options) {
3
+ return process.env["NX_DRY_RUN"] === "true" || (options.dryRun ?? false);
4
+ }
5
+
6
+ export {
7
+ resolveDryRun
8
+ };
@@ -0,0 +1,20 @@
1
+ // src/generators/shared/project-type.ts
2
+ import { parseJson } from "@nx/devkit";
3
+ function resolveProjectType(tree, root, declared) {
4
+ if (declared) return declared === "library" ? "library" : "application";
5
+ const prefix = root === "" || root === "." ? "" : `${root}/`;
6
+ if (tree.exists(`${prefix}tsconfig.lib.json`)) return "library";
7
+ if (tree.exists(`${prefix}tsconfig.app.json`)) return "application";
8
+ const raw = tree.read(`${prefix}package.json`, "utf-8");
9
+ if (raw === null) return "library";
10
+ try {
11
+ const manifest = parseJson(raw);
12
+ if (manifest && !["exports", "main", "module", "bin"].some((key) => Boolean(manifest[key]))) return "application";
13
+ } catch {
14
+ }
15
+ return "library";
16
+ }
17
+
18
+ export {
19
+ resolveProjectType
20
+ };
@@ -0,0 +1,49 @@
1
+ // ../integrations/dist/manifest/manifest.js
2
+ import { existsSync, lstatSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { randomBytes } from "node:crypto";
5
+ var MANIFEST_FILENAME = "archweave-integrations.json";
6
+ function createEmptyManifest() {
7
+ return { integrations: {} };
8
+ }
9
+ function loadManifest(root) {
10
+ const manifestPath = join(root, MANIFEST_FILENAME);
11
+ if (!existsSync(manifestPath)) {
12
+ return createEmptyManifest();
13
+ }
14
+ try {
15
+ const parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
16
+ if (parsed && typeof parsed === "object" && typeof parsed.integrations === "object") {
17
+ return { integrations: parsed.integrations ?? {} };
18
+ }
19
+ return createEmptyManifest();
20
+ } catch {
21
+ return createEmptyManifest();
22
+ }
23
+ }
24
+ function serializeManifest(manifest) {
25
+ return `${JSON.stringify(manifest, null, 2)}
26
+ `;
27
+ }
28
+ function writeManifestAtomic(root, manifest) {
29
+ const finalPath = join(root, MANIFEST_FILENAME);
30
+ if (existsSync(finalPath) && lstatSync(finalPath).isSymbolicLink()) {
31
+ throw new Error(`Refusing to write ${MANIFEST_FILENAME}: the path is a symlink. Remove or replace it with a regular file first.`);
32
+ }
33
+ const suffix = randomBytes(6).toString("hex");
34
+ const tempPath = join(root, `.${MANIFEST_FILENAME}.tmp-${suffix}`);
35
+ try {
36
+ writeFileSync(tempPath, serializeManifest(manifest));
37
+ renameSync(tempPath, finalPath);
38
+ } catch (error) {
39
+ if (existsSync(tempPath)) {
40
+ unlinkSync(tempPath);
41
+ }
42
+ throw error;
43
+ }
44
+ }
45
+
46
+ export {
47
+ loadManifest,
48
+ writeManifestAtomic
49
+ };
@@ -0,0 +1,73 @@
1
+ import {
2
+ loadManifest,
3
+ writeManifestAtomic
4
+ } from "./chunk-U6LAFHSF.js";
5
+ import {
6
+ getCatalogEntry,
7
+ recordMetadataFor,
8
+ verifyClaudeMarketplacePlugin
9
+ } from "./chunk-AQHV7DJS.js";
10
+
11
+ // ../integrations/dist/manifest/record-plan.js
12
+ function entriesEqual(a, b) {
13
+ return JSON.stringify(a) === JSON.stringify(b);
14
+ }
15
+ function buildRecordPlan(input) {
16
+ const isRecordable = input.verification.verified && input.verificationSource === "claude-cli";
17
+ const proposedEntry = isRecordable ? {
18
+ source: input.metadata.source,
19
+ repository: input.metadata.repository,
20
+ version: input.verification.resolvedVersion,
21
+ method: input.metadata.method,
22
+ managedBy: "nx-archweave",
23
+ verification: "passed",
24
+ target: input.target,
25
+ evidenceKind: "claude-cli"
26
+ } : void 0;
27
+ const hasConflict = input.existingEntry !== void 0 && proposedEntry !== void 0 && !entriesEqual(input.existingEntry, proposedEntry);
28
+ return {
29
+ id: input.id,
30
+ target: input.target,
31
+ verificationSource: input.verificationSource,
32
+ currentVerification: input.verification,
33
+ existingEntry: input.existingEntry,
34
+ proposedEntry,
35
+ hasConflict
36
+ };
37
+ }
38
+
39
+ // src/generators/shared/record-pipeline.ts
40
+ async function runRecordPipeline(input) {
41
+ const entry = getCatalogEntry(input.id);
42
+ const metadata = entry === void 0 ? void 0 : recordMetadataFor(entry);
43
+ if (!entry || !metadata) {
44
+ throw new Error(`No manifest metadata is defined for "${input.id}".`);
45
+ }
46
+ const { result: verification, source: verificationSource } = await verifyClaudeMarketplacePlugin(
47
+ entry,
48
+ { runner: input.runner },
49
+ { workspaceRoot: input.workspaceRoot, targetEnvironment: input.target }
50
+ );
51
+ const manifest = loadManifest(input.workspaceRoot);
52
+ const existingEntry = manifest.integrations[input.id];
53
+ const plan = buildRecordPlan({ id: input.id, target: input.target, verificationSource, verification, existingEntry, metadata });
54
+ let wasWritten = false;
55
+ if (input.write && plan.proposedEntry) {
56
+ writeManifestAtomic(input.workspaceRoot, {
57
+ integrations: { ...manifest.integrations, [input.id]: plan.proposedEntry }
58
+ });
59
+ wasWritten = true;
60
+ }
61
+ return {
62
+ verificationSource,
63
+ verification,
64
+ existingEntry,
65
+ proposedEntry: plan.proposedEntry,
66
+ hasConflict: plan.hasConflict,
67
+ wasWritten
68
+ };
69
+ }
70
+
71
+ export {
72
+ runRecordPipeline
73
+ };
@@ -0,0 +1,25 @@
1
+ // src/generators/shared/template-files.ts
2
+ import { existsSync } from "node:fs";
3
+ import { fileURLToPath } from "node:url";
4
+ import { generateFiles } from "@nx/devkit";
5
+ import { createTree } from "@nx/devkit/testing";
6
+ function generatorFilesDir(generator, fromUrl) {
7
+ for (const relative of [`../${generator}/files`, `./generators/${generator}/files`]) {
8
+ const dir = fileURLToPath(new URL(relative, fromUrl));
9
+ if (existsSync(dir)) return dir;
10
+ }
11
+ throw new Error(`The "${generator}" generator's template files are missing next to ${fileURLToPath(fromUrl)}`);
12
+ }
13
+ function renderTemplateFiles(srcFolder, target, substitutions) {
14
+ const scratch = createTree();
15
+ const seeded = new Set(scratch.listChanges().map((change) => change.path));
16
+ generateFiles(scratch, srcFolder, target, substitutions);
17
+ return scratch.listChanges().flatMap(
18
+ (change) => change.type === "CREATE" && change.content !== null && !seeded.has(change.path) ? [{ filePath: change.path, content: change.content.toString("utf-8") }] : []
19
+ ).sort((a, b) => a.filePath.localeCompare(b.filePath));
20
+ }
21
+
22
+ export {
23
+ generatorFilesDir,
24
+ renderTemplateFiles
25
+ };