@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,274 @@
1
+ import {
2
+ resolveProjectType
3
+ } from "./chunk-TXAQ2GJC.js";
4
+ import {
5
+ readBoundaryTags
6
+ } from "./chunk-6ZTIUBB2.js";
7
+ import {
8
+ readToolkitConfig
9
+ } from "./chunk-EXYZLL7A.js";
10
+
11
+ // ../template-engine/dist/frameworks/profiles.js
12
+ var ALL_LAYERS = ["app", "pages", "features", "entities", "shared"];
13
+ var NEXT = {
14
+ id: "next",
15
+ recognised: true,
16
+ // Next.js's own app/ (App Router) directory is the composition root; FSD's Next.js guide
17
+ // names the FSD app and pages layers _app and _pages, since Next.js reads src/app and
18
+ // src/pages as its routers.
19
+ layers: ["pages", "features", "entities", "shared"],
20
+ layerDirs: { app: "_app", pages: "_pages" },
21
+ buildOutputDirs: [".next", "out"],
22
+ platformSuffixes: [],
23
+ routerDirs: ["pages"]
24
+ };
25
+ var REACT_VITE = {
26
+ id: "react-vite",
27
+ recognised: true,
28
+ layers: ALL_LAYERS,
29
+ layerDirs: {},
30
+ buildOutputDirs: ["dist"],
31
+ platformSuffixes: [],
32
+ routerDirs: []
33
+ };
34
+ var EXPO_ROUTER = {
35
+ id: "expo",
36
+ recognised: true,
37
+ layers: ALL_LAYERS,
38
+ layerDirs: { app: "_app" },
39
+ buildOutputDirs: [".expo", "dist"],
40
+ platformSuffixes: ["ios", "android", "native", "web"],
41
+ routerDirs: []
42
+ };
43
+ var EXPO = { ...EXPO_ROUTER, layerDirs: {} };
44
+ var GENERIC = {
45
+ id: "generic",
46
+ recognised: false,
47
+ layers: ALL_LAYERS,
48
+ layerDirs: {},
49
+ buildOutputDirs: ["dist", "build"],
50
+ platformSuffixes: [],
51
+ routerDirs: []
52
+ };
53
+ var PROFILES = { next: NEXT, "react-vite": REACT_VITE, expo: EXPO_ROUTER, generic: GENERIC };
54
+ function profileById(id) {
55
+ return PROFILES[id];
56
+ }
57
+ function allFrameworkProfiles() {
58
+ return Object.values(PROFILES);
59
+ }
60
+ var NEXT_CONFIGS = ["next.config.js", "next.config.mjs", "next.config.ts", "next.config.cjs"];
61
+ var VITE_CONFIGS = ["vite.config.ts", "vite.config.mts", "vite.config.js", "vite.config.mjs"];
62
+ var EXPO_CONFIGS = ["app.config.ts", "app.config.js", "app.config.mjs"];
63
+ function hasExpoKey(input, file) {
64
+ const text = input.read(file);
65
+ if (typeof text !== "string")
66
+ return false;
67
+ try {
68
+ return typeof JSON.parse(text)["expo"] === "object";
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+ function dependsOn(input, manifest, name) {
74
+ const text = input.read(manifest);
75
+ if (typeof text !== "string")
76
+ return false;
77
+ try {
78
+ const parsed = JSON.parse(text);
79
+ return ["dependencies", "devDependencies", "peerDependencies"].some((field) => parsed[field]?.[name] !== void 0);
80
+ } catch {
81
+ return false;
82
+ }
83
+ }
84
+ function detectFramework(input) {
85
+ const prefix = input.projectRoot === "" || input.projectRoot === "." ? "" : `${input.projectRoot}/`;
86
+ const executors = input.executors ?? [];
87
+ if (NEXT_CONFIGS.some((file) => input.exists(`${prefix}${file}`)) || executors.some((executor) => executor.startsWith("@nx/next:"))) {
88
+ return NEXT;
89
+ }
90
+ const dependsAnywhere = (name) => dependsOn(input, `${prefix}package.json`, name) || dependsOn(input, "package.json", name);
91
+ const usesExpo = executors.some((executor) => executor.startsWith("@nx/expo:")) || hasExpoKey(input, `${prefix}app.json`) || EXPO_CONFIGS.some((file) => input.exists(`${prefix}${file}`)) || dependsOn(input, `${prefix}package.json`, "expo");
92
+ if (usesExpo)
93
+ return dependsAnywhere("expo-router") ? EXPO_ROUTER : EXPO;
94
+ const usesReact = dependsAnywhere("react");
95
+ const usesVite = VITE_CONFIGS.some((file) => input.exists(`${prefix}${file}`)) || executors.some((executor) => executor.startsWith("@nx/vite:"));
96
+ if (usesVite && usesReact)
97
+ return REACT_VITE;
98
+ return GENERIC;
99
+ }
100
+
101
+ // src/generators/shared/frontend-app.ts
102
+ import { getProjects } from "@nx/devkit";
103
+
104
+ // ../template-engine/dist/fsd/slice-rules.js
105
+ function toCamelCase(kebabName) {
106
+ return kebabName.split("-").filter((part) => part.length > 0).map((part, index) => index === 0 ? part : part.charAt(0).toUpperCase() + part.slice(1)).join("");
107
+ }
108
+ function resolveSlicePublicApiName(name, publicApiName) {
109
+ return publicApiName ?? toCamelCase(name);
110
+ }
111
+ var IDENTIFIER_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
112
+ var RESERVED_WORDS = /* @__PURE__ */ new Set([
113
+ "await",
114
+ "break",
115
+ "case",
116
+ "catch",
117
+ "class",
118
+ "const",
119
+ "continue",
120
+ "debugger",
121
+ "default",
122
+ "delete",
123
+ "do",
124
+ "else",
125
+ "enum",
126
+ "export",
127
+ "extends",
128
+ "false",
129
+ "finally",
130
+ "for",
131
+ "function",
132
+ "if",
133
+ "implements",
134
+ "import",
135
+ "in",
136
+ "instanceof",
137
+ "interface",
138
+ "let",
139
+ "new",
140
+ "null",
141
+ "package",
142
+ "private",
143
+ "protected",
144
+ "public",
145
+ "return",
146
+ "static",
147
+ "super",
148
+ "switch",
149
+ "this",
150
+ "throw",
151
+ "true",
152
+ "try",
153
+ "typeof",
154
+ "var",
155
+ "void",
156
+ "while",
157
+ "with",
158
+ "yield"
159
+ ]);
160
+ function isUsableSliceApiName(candidate) {
161
+ return IDENTIFIER_PATTERN.test(candidate) && !RESERVED_WORDS.has(candidate);
162
+ }
163
+ var ESSENCE_SEGMENT_NAMES = [
164
+ "components",
165
+ "hooks",
166
+ "helpers",
167
+ "utils",
168
+ "types",
169
+ "constants",
170
+ "consts",
171
+ "interfaces",
172
+ "enums",
173
+ "modals",
174
+ "stores",
175
+ "services"
176
+ ];
177
+ function isEssenceSegmentName(name) {
178
+ return ESSENCE_SEGMENT_NAMES.includes(name);
179
+ }
180
+ var SEGMENT_NAME_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
181
+
182
+ // src/generators/shared/frontend-app.ts
183
+ var baseNameOf = (root) => root.split("/").pop() ?? root;
184
+ function isEndToEnd(root) {
185
+ const dir = baseNameOf(root);
186
+ return dir === "e2e" || dir.endsWith("-e2e");
187
+ }
188
+ function isBackend(root, config, backendTag) {
189
+ return baseNameOf(root) === "api" || (config.tags ?? []).includes(backendTag);
190
+ }
191
+ function prefixOf(root) {
192
+ return root === "" || root === "." ? "" : `${root}/`;
193
+ }
194
+ function sourceRootOf(tree, config) {
195
+ const prefix = prefixOf(config.root);
196
+ const declared = config.sourceRoot?.replace(/\/$/, "");
197
+ const atRoot = declared !== void 0 && (declared === config.root || prefix === "" && (declared === "." || declared === ""));
198
+ if (declared && !atRoot) return declared;
199
+ if (atRoot && !tree.exists(`${prefix}src`)) return prefix === "" ? "." : config.root;
200
+ return `${prefix}src`;
201
+ }
202
+ function frameworkOf(tree, config) {
203
+ return detectFramework({
204
+ exists: (path) => tree.exists(path),
205
+ read: (path) => tree.read(path, "utf-8"),
206
+ projectRoot: config.root,
207
+ executors: Object.values(config.targets ?? {}).flatMap((target) => target.executor ? [target.executor] : [])
208
+ });
209
+ }
210
+ function resolveFrontendApp(tree, explicitProject) {
211
+ let projects;
212
+ try {
213
+ projects = getProjects(tree);
214
+ } catch (error) {
215
+ const message = error instanceof Error ? error.message : String(error);
216
+ const pathMatch = /Cannot parse ([^:]+):/.exec(message);
217
+ return { kind: "invalid-project-json", detail: pathMatch ? pathMatch[1] : message };
218
+ }
219
+ const found = (project2, config2) => {
220
+ const profile = frameworkOf(tree, config2);
221
+ return { kind: "found", project: project2, root: config2.root, sourceRoot: sourceRootOf(tree, config2), framework: profile.id, profile };
222
+ };
223
+ if (explicitProject !== void 0) {
224
+ const config2 = projects.get(explicitProject);
225
+ if (config2) return found(explicitProject, config2);
226
+ const rootApp = inferredRootApp(tree, projects);
227
+ return rootApp?.kind === "found" && rootApp.project === explicitProject ? rootApp : { kind: "not-found", project: explicitProject };
228
+ }
229
+ const backendTag = readBoundaryTags(readToolkitConfig(tree)).backend;
230
+ const eligible = [...projects.entries()].filter(([, config2]) => !isEndToEnd(config2.root) && !isBackend(config2.root, config2, backendTag));
231
+ const declared = eligible.filter(([, config2]) => config2.projectType === "application");
232
+ const inferred = eligible.filter(([, config2]) => {
233
+ if (config2.projectType !== void 0) return false;
234
+ if (config2.root === "" || config2.root === ".") return frameworkOf(tree, config2).recognised;
235
+ return resolveProjectType(tree, config2.root, void 0) === "application";
236
+ });
237
+ const candidates = (declared.length > 0 ? declared : inferred).sort(([a], [b]) => a.localeCompare(b));
238
+ if (candidates.length === 0) {
239
+ const rootApp = inferredRootApp(tree, projects);
240
+ if (rootApp !== null) return rootApp;
241
+ const otherProjects = [...projects.keys()].filter((name) => !isEndToEnd(projects.get(name)?.root ?? "")).sort();
242
+ return { kind: "none", otherProjects };
243
+ }
244
+ if (candidates.length > 1) return { kind: "ambiguous", candidates: candidates.map(([name]) => name) };
245
+ const [project, config] = candidates[0];
246
+ return found(project, config);
247
+ }
248
+ function inferredRootApp(tree, projects) {
249
+ if ([...projects.values()].some((config2) => config2.root === "" || config2.root === ".")) return null;
250
+ const raw = tree.read("package.json", "utf-8");
251
+ if (raw === null) return null;
252
+ let name;
253
+ try {
254
+ name = JSON.parse(raw).name;
255
+ } catch {
256
+ return null;
257
+ }
258
+ if (typeof name !== "string" || name === "") return null;
259
+ const config = { name, root: "." };
260
+ const framework = frameworkOf(tree, config);
261
+ if (!framework.recognised) return null;
262
+ return { kind: "found", project: name, root: ".", sourceRoot: sourceRootOf(tree, config), framework: framework.id, profile: framework, inferredRoot: true };
263
+ }
264
+
265
+ export {
266
+ profileById,
267
+ allFrameworkProfiles,
268
+ resolveSlicePublicApiName,
269
+ isUsableSliceApiName,
270
+ isEssenceSegmentName,
271
+ SEGMENT_NAME_PATTERN,
272
+ sourceRootOf,
273
+ resolveFrontendApp
274
+ };
@@ -0,0 +1,55 @@
1
+ // ../shared/dist/lib/spawnable-command.js
2
+ import { statSync } from "node:fs";
3
+ import { win32 } from "node:path";
4
+ function isFile(path) {
5
+ try {
6
+ return statSync(path).isFile();
7
+ } catch {
8
+ return false;
9
+ }
10
+ }
11
+ var DEFAULT_ENV = { platform: process.platform, env: process.env, isFile };
12
+ function envValue(env, name) {
13
+ const key = Object.keys(env).find((candidate) => candidate.toUpperCase() === name);
14
+ return key === void 0 ? void 0 : env[key];
15
+ }
16
+ function resolveWindowsCommand(command, environment) {
17
+ const exts = (envValue(environment.env, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean);
18
+ const candidates = (base) => win32.extname(base) !== "" ? [base] : exts.map((ext) => base + ext);
19
+ if (win32.isAbsolute(command) || /[\\/]/.test(command)) {
20
+ return candidates(command).find(environment.isFile);
21
+ }
22
+ const dirs = (envValue(environment.env, "PATH") ?? "").split(";").filter(Boolean);
23
+ for (const dir of dirs) {
24
+ const found = candidates(win32.join(dir, command)).find(environment.isFile);
25
+ if (found !== void 0)
26
+ return found;
27
+ }
28
+ return void 0;
29
+ }
30
+ var META_CHARS = /([()\][%!^"`<>&|;, *?])/g;
31
+ var BIN_SHIM = /node_modules[\\/]\.bin[\\/][^\\/]+\.cmd$/i;
32
+ function escapeCmdArgument(arg, doubleEscape = false) {
33
+ let quoted = arg.replace(/(\\*)"/g, '$1$1\\"');
34
+ quoted = quoted.replace(/(\\*)$/, "$1$1");
35
+ const escaped = `"${quoted}"`.replace(META_CHARS, "^$1");
36
+ return doubleEscape ? escaped.replace(META_CHARS, "^$1") : escaped;
37
+ }
38
+ function spawnableCommand(command, args, environment = DEFAULT_ENV) {
39
+ if (environment.platform !== "win32")
40
+ return { command, args: [...args] };
41
+ const resolved = resolveWindowsCommand(command, environment);
42
+ if (resolved === void 0 || !/\.(cmd|bat)$/i.test(resolved))
43
+ return { command, args: [...args] };
44
+ const doubleEscape = BIN_SHIM.test(resolved);
45
+ const line = [resolved.replace(META_CHARS, "^$1"), ...args.map((arg) => escapeCmdArgument(arg, doubleEscape))].join(" ");
46
+ return {
47
+ command: envValue(environment.env, "COMSPEC") ?? "cmd.exe",
48
+ args: ["/d", "/s", "/c", `"${line}"`],
49
+ windowsVerbatimArguments: true
50
+ };
51
+ }
52
+
53
+ export {
54
+ spawnableCommand
55
+ };
@@ -0,0 +1,114 @@
1
+ // src/generators/add-review/render.ts
2
+ var DEPENDABOT_PATH = ".github/dependabot.yml";
3
+ var PROVIDER_STATUS_URL = "https://github.com/clearlydev/nx-archweave/blob/main/docs/pr-review.md#provider-status";
4
+ function renderLineDiff(existing, generated) {
5
+ const a = existing.split("\n");
6
+ const b = generated.split("\n");
7
+ const m = a.length;
8
+ const n = b.length;
9
+ const lcs = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
10
+ for (let i2 = m - 1; i2 >= 0; i2--) {
11
+ for (let j2 = n - 1; j2 >= 0; j2--) {
12
+ lcs[i2][j2] = a[i2] === b[j2] ? lcs[i2 + 1][j2 + 1] + 1 : Math.max(lcs[i2 + 1][j2], lcs[i2][j2 + 1]);
13
+ }
14
+ }
15
+ const out = ["--- existing", "+++ generated"];
16
+ let i = 0;
17
+ let j = 0;
18
+ while (i < m && j < n) {
19
+ if (a[i] === b[j]) {
20
+ out.push(` ${a[i]}`);
21
+ i++;
22
+ j++;
23
+ } else if (lcs[i + 1][j] >= lcs[i][j + 1]) {
24
+ out.push(`- ${a[i]}`);
25
+ i++;
26
+ } else {
27
+ out.push(`+ ${b[j]}`);
28
+ j++;
29
+ }
30
+ }
31
+ while (i < m) out.push(`- ${a[i++]}`);
32
+ while (j < n) out.push(`+ ${b[j++]}`);
33
+ return out.join("\n");
34
+ }
35
+ var WORKFLOW_ACTION_LINES = {
36
+ created: "created",
37
+ overwritten: "overwritten with the generated version (per --onConflict=overwrite)",
38
+ unchanged: "unchanged (already matches the generated version)",
39
+ proposed: "NOT written \u2014 differs from the generated version (merge proposal below)",
40
+ skipped: "left as-is (per --onConflict=skip)",
41
+ alternate: "generated alongside the existing file",
42
+ aborted: "NOT written"
43
+ };
44
+ var CONFIG_ACTION_LINES = {
45
+ created: "created with the review field",
46
+ updated: "review field updated",
47
+ unchanged: "review field unchanged",
48
+ "not-updated": "NOT updated \u2014 kept consistent with the workflow file that is actually in effect",
49
+ aborted: "NOT updated"
50
+ };
51
+ function renderAddReviewReport(report) {
52
+ const lines = [];
53
+ if (report.packageManagerNote !== void 0) {
54
+ lines.push(`Note: ${report.packageManagerNote}`);
55
+ }
56
+ if (report.workflowAction === "aborted") {
57
+ lines.push("add-review aborted \u2014 nothing was written.");
58
+ lines.push(` toolkit.config.json: ${report.configError ?? "unusable"}`);
59
+ lines.push(" Fix the config file manually, then rerun the generator.");
60
+ return lines.join("\n");
61
+ }
62
+ if (report.dryRun) {
63
+ lines.push("add-review dry-run \u2014 no files were written.");
64
+ lines.push("");
65
+ lines.push("Generated workflow YAML:");
66
+ lines.push(report.workflowYaml ?? "");
67
+ lines.push("");
68
+ lines.push("toolkit.config.json review field:");
69
+ lines.push(report.configSnippetJson ?? "");
70
+ lines.push("");
71
+ lines.push("Effective decision:");
72
+ }
73
+ lines.push(` ${report.workflowPath}: ${WORKFLOW_ACTION_LINES[report.workflowAction]}`);
74
+ lines.push(` toolkit.config.json: ${CONFIG_ACTION_LINES[report.configAction]}`);
75
+ if (report.workflowAction === "proposed" && report.diff) {
76
+ lines.push("");
77
+ lines.push(report.diff);
78
+ lines.push("");
79
+ lines.push("To resolve, rerun with one of:");
80
+ lines.push(" --onConflict=overwrite replace the existing file with the generated version");
81
+ lines.push(" --onConflict=skip keep the existing file");
82
+ lines.push(" --onConflict=alternate-filename write the generated version alongside it");
83
+ }
84
+ if (report.dependabot === "created") {
85
+ lines.push(` ${DEPENDABOT_PATH}: created \u2014 Dependabot proposes newer pins for the workflow's actions`);
86
+ } else if (report.dependabot === "present") {
87
+ lines.push(` ${DEPENDABOT_PATH}: already updates github-actions`);
88
+ } else if (report.dependabot === "proposed") {
89
+ lines.push(` ${DEPENDABOT_PATH}: NOT changed \u2014 it has no github-actions entry. The workflow pins each action`);
90
+ lines.push(" to a commit SHA; add this entry under `updates:` so those pins get update pull requests:");
91
+ lines.push("");
92
+ lines.push(report.dependabotProposal ?? "");
93
+ }
94
+ if (report.workflowAction === "alternate") {
95
+ lines.push("");
96
+ lines.push(" Review the generated file, then replace the main workflow file with it yourself;");
97
+ lines.push(" the config stays pointing at the workflow that is actually in effect until you do.");
98
+ }
99
+ lines.push("");
100
+ lines.push(`Note: the review workflow stays green-skipped until you register the ${report.requiredSecretName} secret.`);
101
+ if (report.betaProvider !== void 0) {
102
+ lines.push(`Note: the ${report.betaProvider} provider is in beta \u2014 its workflow hasn't finished a review end to end on`);
103
+ lines.push(`GitHub Actions yet. Status, costs and known issues: ${PROVIDER_STATUS_URL}`);
104
+ }
105
+ lines.push("Note: this workflow runs with elevated permissions only after it is merged to the default branch \u2014");
106
+ lines.push("merging is the first real validation.");
107
+ return lines.join("\n");
108
+ }
109
+
110
+ export {
111
+ DEPENDABOT_PATH,
112
+ renderLineDiff,
113
+ renderAddReviewReport
114
+ };
@@ -0,0 +1,30 @@
1
+ import {
2
+ TOOLKIT_CONFIG_PATH,
3
+ workspacePackageManager
4
+ } from "./chunk-EXYZLL7A.js";
5
+ import {
6
+ packageManagerCommands
7
+ } from "./chunk-FQHFT5IH.js";
8
+
9
+ // src/generators/shared/run-nx.ts
10
+ import { existsSync, readFileSync } from "node:fs";
11
+ import { join } from "node:path";
12
+ function runNxFor(exists, read) {
13
+ let config = null;
14
+ try {
15
+ const parsed = JSON.parse(read(TOOLKIT_CONFIG_PATH) ?? "null");
16
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) config = parsed;
17
+ } catch {
18
+ }
19
+ return packageManagerCommands(workspacePackageManager(exists, read, config) ?? "pnpm").runNx;
20
+ }
21
+ function diskRunNx(root) {
22
+ return runNxFor(
23
+ (path) => existsSync(join(root, path)),
24
+ (path) => existsSync(join(root, path)) ? readFileSync(join(root, path), "utf-8") : void 0
25
+ );
26
+ }
27
+
28
+ export {
29
+ diskRunNx
30
+ };
@@ -0,0 +1,99 @@
1
+ // src/eslint/fsd-policy.ts
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ var PRESETS = {
5
+ basic: {
6
+ sliceGroups: { auto: true, include: [], exclude: [] },
7
+ sharedPublicApi: "segment",
8
+ testFiles: false,
9
+ segments: [],
10
+ platformSuffixes: [],
11
+ routerDirs: []
12
+ },
13
+ practical: {
14
+ sliceGroups: { auto: true, include: [], exclude: [] },
15
+ sharedPublicApi: "file",
16
+ testFiles: ["**/*.{spec,test}.*", "**/__tests__/**"],
17
+ segments: [],
18
+ platformSuffixes: [],
19
+ routerDirs: []
20
+ }
21
+ };
22
+ var isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
23
+ function resolveFsdPolicy(recorded, overrides = {}) {
24
+ const fsd = typeof recorded === "object" && recorded !== null ? recorded : {};
25
+ const preset = fsd["preset"] === "practical" ? "practical" : "basic";
26
+ const policy = { ...PRESETS[preset] };
27
+ const groups = fsd["sliceGroups"];
28
+ if (groups === false) policy.sliceGroups = false;
29
+ else if (groups === "auto") policy.sliceGroups = { auto: true, include: [], exclude: [] };
30
+ else if (typeof groups === "object" && groups !== null) {
31
+ const value = groups;
32
+ policy.sliceGroups = {
33
+ auto: value["auto"] !== false,
34
+ include: isStringArray(value["include"]) ? value["include"] : [],
35
+ exclude: isStringArray(value["exclude"]) ? value["exclude"] : []
36
+ };
37
+ }
38
+ const shared = fsd["sharedPublicApi"];
39
+ if (shared === "segment" || shared === "component" || shared === "file") policy.sharedPublicApi = shared;
40
+ const tests = fsd["testFiles"];
41
+ if (tests === false || isStringArray(tests)) policy.testFiles = tests;
42
+ if (isStringArray(fsd["segments"])) policy.segments = fsd["segments"];
43
+ if (isStringArray(fsd["platformSuffixes"])) policy.platformSuffixes = fsd["platformSuffixes"];
44
+ if (isStringArray(fsd["routerDirs"])) policy.routerDirs = fsd["routerDirs"];
45
+ for (const [key, value] of Object.entries(overrides)) {
46
+ if (value !== void 0) policy[key] = value;
47
+ }
48
+ return policy;
49
+ }
50
+ function readRecordedFsd(from) {
51
+ for (let dir = from; ; dir = dirname(dir)) {
52
+ const file = join(dir, "toolkit.config.json");
53
+ if (existsSync(file)) {
54
+ try {
55
+ return JSON.parse(readFileSync(file, "utf-8"))["fsd"];
56
+ } catch {
57
+ return void 0;
58
+ }
59
+ }
60
+ if (dirname(dir) === dir) return void 0;
61
+ }
62
+ }
63
+ var escapeLiteral = (text) => text.replace(/[.+^$()|[\]\\{}]/g, "\\$&");
64
+ function wildcardsToRegExp(glob) {
65
+ let source = "";
66
+ for (let i = 0; i < glob.length; i++) {
67
+ const ch = glob[i];
68
+ if (ch === "*" && glob[i + 1] === "*") {
69
+ const slash = glob[i + 2] === "/";
70
+ source += slash ? "(?:.*/)?" : ".*";
71
+ i += slash ? 2 : 1;
72
+ } else if (ch === "*") source += "[^/]*";
73
+ else if (ch === "?") source += "[^/]";
74
+ else source += escapeLiteral(ch);
75
+ }
76
+ return source;
77
+ }
78
+ function globToRegExp(glob) {
79
+ let source = "";
80
+ let rest = glob;
81
+ for (; ; ) {
82
+ const open = rest.indexOf("{");
83
+ const close = open === -1 ? -1 : rest.indexOf("}", open);
84
+ if (open === -1 || close === -1) {
85
+ source += wildcardsToRegExp(rest);
86
+ break;
87
+ }
88
+ source += wildcardsToRegExp(rest.slice(0, open));
89
+ source += `(?:${rest.slice(open + 1, close).split(",").map(wildcardsToRegExp).join("|")})`;
90
+ rest = rest.slice(close + 1);
91
+ }
92
+ return new RegExp(`^${source}$`);
93
+ }
94
+
95
+ export {
96
+ resolveFsdPolicy,
97
+ readRecordedFsd,
98
+ globToRegExp
99
+ };