@clearlydev/nx-archweave 0.3.2 → 0.4.0

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 (47) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/review-verdict.js +8 -249
  3. package/dist/eslint/index.js +28 -321
  4. package/dist/generators/_chunks/chunk-2WSX5YNB.js +274 -0
  5. package/dist/generators/_chunks/chunk-34V6HAJT.js +55 -0
  6. package/dist/generators/_chunks/chunk-3A6RZUCZ.js +114 -0
  7. package/dist/generators/_chunks/chunk-47T7NOPP.js +30 -0
  8. package/dist/generators/_chunks/chunk-4FJ7CLEU.js +189 -0
  9. package/dist/generators/_chunks/chunk-5MI3O4VZ.js +99 -0
  10. package/dist/generators/_chunks/chunk-6ZTIUBB2.js +139 -0
  11. package/dist/generators/_chunks/chunk-AIJCJ7JK.js +203 -0
  12. package/dist/generators/_chunks/chunk-ALSXKTLM.js +1098 -0
  13. package/dist/generators/_chunks/chunk-AQHV7DJS.js +656 -0
  14. package/dist/generators/_chunks/chunk-C2VVUWBA.js +386 -0
  15. package/dist/generators/_chunks/chunk-EXYZLL7A.js +234 -0
  16. package/dist/generators/_chunks/chunk-FQHFT5IH.js +50 -0
  17. package/dist/generators/_chunks/chunk-H222FPLK.js +80 -0
  18. package/dist/generators/_chunks/chunk-IIDOBI42.js +616 -0
  19. package/dist/generators/_chunks/chunk-L2RZ2LBO.js +132 -0
  20. package/dist/generators/_chunks/chunk-MQNQJOWA.js +217 -0
  21. package/dist/generators/_chunks/chunk-QQNDYJTR.js +243 -0
  22. package/dist/generators/_chunks/chunk-SFXU6IUS.js +0 -0
  23. package/dist/generators/_chunks/chunk-SNBIVIMI.js +89 -0
  24. package/dist/generators/_chunks/chunk-TUN34LAQ.js +8 -0
  25. package/dist/generators/_chunks/chunk-TXAQ2GJC.js +20 -0
  26. package/dist/generators/_chunks/chunk-U6LAFHSF.js +49 -0
  27. package/dist/generators/_chunks/chunk-URV6FLUH.js +73 -0
  28. package/dist/generators/_chunks/chunk-YNMLB4DL.js +25 -0
  29. package/dist/generators/_chunks/chunk-YY2UESLM.js +282 -0
  30. package/dist/generators/add-agent-rules/generator.js +11 -842
  31. package/dist/generators/add-backend/generator.js +11 -906
  32. package/dist/generators/add-fsd-lite/generator.js +12 -801
  33. package/dist/generators/add-github-templates/generator.js +13 -116
  34. package/dist/generators/add-integration/generator.js +15 -743
  35. package/dist/generators/add-review/generator.js +12 -1231
  36. package/dist/generators/allow-builds/generator.js +7 -71
  37. package/dist/generators/doctor/generator.js +106 -2044
  38. package/dist/generators/entity/generator.js +15 -604
  39. package/dist/generators/feature/generator.js +15 -604
  40. package/dist/generators/init/generator.js +68 -3376
  41. package/dist/generators/install-integration/generator.js +35 -871
  42. package/dist/generators/page/generator.js +15 -604
  43. package/dist/generators/record-integration/generator.js +12 -778
  44. package/dist/generators/shared/generator.js +15 -604
  45. package/dist/generators/widget/generator.js +15 -604
  46. package/dist/index.js +5 -663
  47. package/package.json +1 -1
@@ -1,804 +1,15 @@
1
- // src/generators/add-fsd-lite/generator.ts
2
- import { posix } from "node:path";
3
-
4
- // ../shared/dist/lib/toolkit-config.js
5
- function readFsdEnforcement(fsd) {
6
- if (typeof fsd !== "object" || fsd === null)
7
- return void 0;
8
- const enforcement = fsd["enforcement"];
9
- return enforcement === "error" || enforcement === "warn" ? enforcement : void 0;
10
- }
11
-
12
- // ../template-engine/dist/environment/package-manager.js
13
- var LOCKFILES = [
14
- ["yarn", ["yarn.lock"]],
15
- ["bun", ["bun.lock", "bun.lockb"]],
16
- ["npm", ["package-lock.json"]]
17
- ];
18
- function detectWorkspacePackageManager(exists, read = () => void 0) {
19
- if (exists("pnpm-lock.yaml") || exists("pnpm-workspace.yaml"))
20
- return "pnpm";
21
- const found = LOCKFILES.filter(([, files]) => files.some((file) => exists(file))).map(([pm]) => pm);
22
- if (found.length <= 1)
23
- return found[0] ?? null;
24
- const declared = /"packageManager"\s*:\s*"(npm|yarn|bun)@/.exec(read("package.json") ?? "")?.[1];
25
- const named = found.find((pm) => pm === declared);
26
- if (named)
27
- return named;
28
- return found.includes("npm") ? "npm" : found[0];
29
- }
30
- function detectYarnFlavor(exists, read) {
31
- if (exists(".yarnrc.yml"))
32
- return "berry";
33
- if (/^__metadata:/m.test(read("yarn.lock") ?? ""))
34
- return "berry";
35
- const major = /"packageManager"\s*:\s*"yarn@(\d+)\./.exec(read("package.json") ?? "")?.[1];
36
- return major !== void 0 && Number(major) >= 2 ? "berry" : "classic";
37
- }
38
- function packageManagerCommands(pm, flavor = "classic") {
39
- switch (pm) {
40
- case "pnpm":
41
- return { addDevAtRoot: (spec) => `pnpm add -D -w ${spec}`, addAtRoot: (spec) => `pnpm add -w ${spec}`, runNx: "pnpm nx", install: "pnpm install", workspaceRegistration: "pnpm-workspace.yaml" };
42
- case "yarn":
43
- return {
44
- addDevAtRoot: (spec) => flavor === "berry" ? `yarn add -D ${spec}` : `yarn add -D -W ${spec}`,
45
- addAtRoot: (spec) => flavor === "berry" ? `yarn add ${spec}` : `yarn add -W ${spec}`,
46
- runNx: "yarn nx",
47
- install: "yarn install",
48
- workspaceRegistration: "package.json workspaces"
49
- };
50
- case "bun":
51
- return { addDevAtRoot: (spec) => `bun add -d ${spec}`, addAtRoot: (spec) => `bun add ${spec}`, runNx: "bun nx", install: "bun install", workspaceRegistration: "package.json workspaces" };
52
- case "npm":
53
- return { addDevAtRoot: (spec) => `npm install -D ${spec}`, addAtRoot: (spec) => `npm install ${spec}`, runNx: "npm exec nx --", install: "npm install", workspaceRegistration: "package.json workspaces" };
54
- }
55
- }
56
-
57
- // ../template-engine/dist/backend/eslint-boundaries.js
58
- var DEFAULT_BOUNDARY_TAGS = { frontend: "scope:frontend", backend: "scope:backend", shared: "scope:shared" };
59
- function readBoundaryTags(config) {
60
- const boundaries = config?.["boundaries"];
61
- const tags = typeof boundaries === "object" && boundaries !== null ? boundaries["tags"] : void 0;
62
- const pick = (role) => {
63
- const value = typeof tags === "object" && tags !== null ? tags[role] : void 0;
64
- return typeof value === "string" && value.trim() !== "" ? value : DEFAULT_BOUNDARY_TAGS[role];
65
- };
66
- return { frontend: pick("frontend"), backend: pick("backend"), shared: pick("shared") };
67
- }
68
- function scopeConstraints(tags = DEFAULT_BOUNDARY_TAGS) {
69
- return [
70
- { sourceTag: tags.frontend, notDependOnLibsWithTags: [tags.backend] },
71
- { sourceTag: tags.backend, notDependOnLibsWithTags: [tags.frontend] },
72
- { sourceTag: tags.shared, notDependOnLibsWithTags: [tags.frontend, tags.backend] }
73
- ];
74
- }
75
- var SCOPE_CONSTRAINTS = scopeConstraints();
76
- var ESLINT_CONFIG_CANDIDATES = ["eslint.config.mjs", "eslint.config.js", "eslint.config.cjs"];
77
- function maskComments(text) {
78
- const out = text.split("");
79
- let mode = "code";
80
- let quote = "";
81
- for (let i = 0; i < text.length; i++) {
82
- const c = text[i];
83
- const d = text[i + 1];
84
- if (mode === "code") {
85
- if (c === "'" || c === '"' || c === "`") {
86
- mode = "string";
87
- quote = c;
88
- } else if (c === "/" && d === "/") {
89
- mode = "line";
90
- out[i] = " ";
91
- } else if (c === "/" && d === "*") {
92
- mode = "block";
93
- out[i] = " ";
94
- }
95
- } else if (mode === "string") {
96
- if (c === "\\") {
97
- i++;
98
- } else if (c === quote) {
99
- mode = "code";
100
- }
101
- } else if (mode === "line") {
102
- if (c === "\n") {
103
- mode = "code";
104
- } else {
105
- out[i] = " ";
106
- }
107
- } else {
108
- if (c === "*" && d === "/") {
109
- out[i] = " ";
110
- out[i + 1] = " ";
111
- i++;
112
- mode = "code";
113
- } else if (c !== "\n") {
114
- out[i] = " ";
115
- }
116
- }
117
- }
118
- return out.join("");
119
- }
120
-
121
- // ../templates/dist/fsd/fsd-eslint.js
122
- var FSD_ESLINT_MODULE = "@clearlydev/nx-archweave/eslint";
123
- function buildFsdEslintImportLine() {
124
- return `import { fsdBoundaries } from '${FSD_ESLINT_MODULE}';`;
125
- }
126
- function buildFsdEslintEntry(severity, root = "src", framework = {}) {
127
- const list = (key, values) => values === void 0 || values.length === 0 ? "" : `, ${key}: [${values.map((value) => `'${value}'`).join(", ")}]`;
128
- return `...fsdBoundaries({ severity: '${severity}', cwd: import.meta.dirname, root: '${root}'${list("platformSuffixes", framework.platformSuffixes)}${list("routerDirs", framework.routerDirs)} }),`;
129
- }
130
- function buildFsdEslintSnippet({ severity, locale, root, framework }) {
131
- const lines = locale === "ko" ? [
132
- "// nx-archweave FSD \uB808\uC774\uC5B4 \uADDC\uCE59 \u2014 \uD504\uB860\uD2B8\uC5D4\uB4DC \uC571\uC758 eslint.config.mjs\uC5D0 \uC9C1\uC811 \uB123\uC73C\uC138\uC694:",
133
- "// 1) \uB9C8\uC9C0\uB9C9 import \uB4A4\uC5D0 \uC544\uB798 import\uB97C,",
134
- "// 2) \uC124\uC815 \uBC30\uC5F4(export default [...], \uB610\uB294 export default \uD558\uB294 \uBCC0\uC218\uC758 \uBC30\uC5F4)\uC758 \uB9C8\uC9C0\uB9C9 \uD56D\uBAA9\uC73C\uB85C \uC544\uB798 spread\uB97C \uCD94\uAC00\uD569\uB2C8\uB2E4."
135
- ] : [
136
- "// nx-archweave FSD layer rules \u2014 add these to the frontend app's eslint.config.mjs yourself:",
137
- "// 1) the import after the last import,",
138
- "// 2) the spread as the last element of the config array (export default [...], or the array your config exports by name)."
139
- ];
140
- return [...lines, buildFsdEslintImportLine(), buildFsdEslintEntry(severity, root, framework)].join("\n");
141
- }
142
- var LAYER_GUIDE_EN = {
143
- app: "composition root: providers, routing, global styles (the framework entry point lives here)",
144
- pages: "one slice per screen, composed from the layers below",
145
- features: "one slice per user-facing capability (add-to-cart, sign-in)",
146
- entities: "one slice per business object (user, product)",
147
- shared: "segments, not slices: ui, api, lib, model, config \u2014 named by purpose"
148
- };
149
- var LAYER_GUIDE_KO = {
150
- app: "\uC870\uD569 \uB8E8\uD2B8: providers, \uB77C\uC6B0\uD305, \uC804\uC5ED \uC2A4\uD0C0\uC77C (\uD504\uB808\uC784\uC6CC\uD06C \uC9C4\uC785\uC810\uC774 \uC5EC\uAE30 \uC788\uC74C)",
151
- pages: "\uD654\uBA74 \uD558\uB098\uB2F9 \uC2AC\uB77C\uC774\uC2A4 \uD558\uB098 \u2014 \uC544\uB798 \uB808\uC774\uC5B4\uB4E4\uC744 \uC870\uD569",
152
- features: "\uC0AC\uC6A9\uC790 \uAE30\uB2A5 \uD558\uB098\uB2F9 \uC2AC\uB77C\uC774\uC2A4 \uD558\uB098 (add-to-cart, sign-in)",
153
- entities: "\uBE44\uC988\uB2C8\uC2A4 \uAC1D\uCCB4 \uD558\uB098\uB2F9 \uC2AC\uB77C\uC774\uC2A4 \uD558\uB098 (user, product)",
154
- shared: "\uC2AC\uB77C\uC774\uC2A4\uAC00 \uC544\uB2C8\uB77C \uC138\uADF8\uBA3C\uD2B8: ui, api, lib, model, config \u2014 \uBAA9\uC801\uC73C\uB85C \uC774\uB984 \uC9D3\uAE30"
155
- };
156
- function buildFsdLayerGuide({ layers, directories, sourceRoot, locale }) {
157
- const guide = locale === "ko" ? LAYER_GUIDE_KO : LAYER_GUIDE_EN;
158
- const width = Math.max(...directories.map((d) => d.length));
159
- const rows = layers.map((layer, index) => ` ${sourceRoot}/${directories[index].padEnd(width)} ${guide[layer] ?? ""}`);
160
- const footer = locale === "ko" ? [
161
- "\uB808\uC774\uC5B4 \uD3F4\uB354\uB294 \uCCAB \uC2AC\uB77C\uC774\uC2A4\uAC00 \uC0DD\uAE38 \uB54C \uB9CC\uB4E4\uC5B4\uC9D1\uB2C8\uB2E4 (\uC815\uC2DD FSD):",
162
- " nx g @clearlydev/nx-archweave:feature --name=<name> (page, entity, shared\uB3C4 \uAC19\uC740 \uBC29\uC2DD; --segments=ui,api)",
163
- " widgets/ \uB808\uC774\uC5B4\uB294 \uAE30\uBCF8 \uBC94\uC704 \uBC16\uC774\uC9C0\uB9CC nx g @clearlydev/nx-archweave:widget \uC73C\uB85C \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
164
- "\uC704\uC5D0\uC11C \uC544\uB798\uB85C\uB9CC import\uD560 \uC218 \uC788\uACE0, \uAC19\uC740 \uB808\uC774\uC5B4\uC758 \uC2AC\uB77C\uC774\uC2A4\uB07C\uB9AC\uB294 import\uD558\uC9C0 \uC54A\uC73C\uBA70, \uC2AC\uB77C\uC774\uC2A4\uB294",
165
- "index.ts\uB97C \uD1B5\uD574\uC11C\uB9CC import\uD569\uB2C8\uB2E4 \u2014 archweave/fsd-boundaries ESLint \uADDC\uCE59\uC774 \uC704\uBC18\uC744 \uC54C\uB824 \uC90D\uB2C8\uB2E4."
166
- ] : [
167
- "Layer directories appear with their first slice (canonical FSD):",
168
- " nx g @clearlydev/nx-archweave:feature --name=<name> (page, entity and shared work the same way; --segments=ui,api)",
169
- " widgets/ is outside the default scope but one command away: nx g @clearlydev/nx-archweave:widget",
170
- "Imports go downward only, slices on one layer never import each other, and a slice is",
171
- "imported through its index.ts \u2014 the archweave/fsd-boundaries ESLint rule reports violations."
172
- ];
173
- return [...rows, ...footer].join("\n");
174
- }
175
-
176
- // ../templates/dist/fsd/fsd-steiger.js
177
- var STEIGER_DEPENDENCIES = {
178
- steiger: "^0.7.0",
179
- "@feature-sliced/steiger-plugin": "^0.8.0"
180
- };
181
- var STEIGER_CONFIG_FILE = "steiger.config.mjs";
182
- var FSD_CHECK_TARGET = "fsd-check";
183
- function buildFsdCheckTarget(sourceRootName = "src") {
184
- return { command: `steiger ${sourceRootName}`, options: { cwd: "{projectRoot}" } };
185
- }
186
- function buildSteigerConfig({ renamedLayerDirs, locale }) {
187
- const ko = locale === "ko";
188
- const lines = [
189
- "import { defineConfig } from 'steiger';",
190
- "import fsd from '@feature-sliced/steiger-plugin';",
191
- "",
192
- ko ? "// nx-archweave: \uC815\uC2DD FSD \uADDC\uCE59 \uC804\uCCB4(recommended). \uAD6C\uC870\uB294 generator\uAC00 \uC815\uC2DD\uB300\uB85C \uB9CC\uB4E4\uBBC0\uB85C \uADF8\uB300\uB85C \uB9DE\uBB3C\uB9BD\uB2C8\uB2E4." : "// nx-archweave: the canonical rule set (recommended). The generators scaffold canonical FSD, so it fits as is.",
193
- "export default defineConfig([",
194
- " ...fsd.configs.recommended,",
195
- " {",
196
- " rules: {",
197
- ko ? " // \uC544\uBB34\uB3C4 \uCC38\uC870\uD558\uC9C0 \uC54A\uB294 \uC2AC\uB77C\uC774\uC2A4 = \uBC29\uAE08 \uC0DD\uC131\uD55C \uC2AC\uB77C\uC774\uC2A4. \uACBD\uACE0\uB85C \uBCF4\uC774\uB418 \uAC80\uC0AC\uB97C \uB9C9\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4." : " // a slice nothing references yet is every freshly generated slice: visible, not blocking",
198
- " 'fsd/insignificant-slice': 'warn',",
199
- ...renamedLayerDirs.length > 0 ? [
200
- ko ? ` // ${renamedLayerDirs.join(", ")}: \uD504\uB808\uC784\uC6CC\uD06C \uB77C\uC6B0\uD130\uC640 \uACB9\uCE58\uC9C0 \uC54A\uAC8C \uC774\uB984\uC744 \uBC14\uAFBC \uB808\uC774\uC5B4 (FSD \uACF5\uC2DD \uBA85\uBA85) \u2014 steiger 0.7\uC740 \uC544\uC9C1 \uC624\uD0C0\uB85C \uBD05\uB2C8\uB2E4.` : ` // ${renamedLayerDirs.join(", ")}: layers renamed out of the framework router's way (FSD's own naming) \u2014 steiger 0.7 still reads them as typos`,
201
- " 'fsd/typo-in-layer-name': 'off',"
202
- ] : [],
203
- " },",
204
- " },",
205
- "]);",
206
- ""
207
- ];
208
- return lines.join("\n");
209
- }
210
-
211
- // ../template-engine/dist/frameworks/profiles.js
212
- var ALL_LAYERS = ["app", "pages", "features", "entities", "shared"];
213
- var NEXT = {
214
- id: "next",
215
- recognised: true,
216
- // Next.js's own app/ (App Router) directory is the composition root; FSD's Next.js guide
217
- // names the FSD app and pages layers _app and _pages, since Next.js reads src/app and
218
- // src/pages as its routers.
219
- layers: ["pages", "features", "entities", "shared"],
220
- layerDirs: { app: "_app", pages: "_pages" },
221
- buildOutputDirs: [".next", "out"],
222
- platformSuffixes: [],
223
- routerDirs: ["pages"]
224
- };
225
- var REACT_VITE = {
226
- id: "react-vite",
227
- recognised: true,
228
- layers: ALL_LAYERS,
229
- layerDirs: {},
230
- buildOutputDirs: ["dist"],
231
- platformSuffixes: [],
232
- routerDirs: []
233
- };
234
- var EXPO_ROUTER = {
235
- id: "expo",
236
- recognised: true,
237
- layers: ALL_LAYERS,
238
- layerDirs: { app: "_app" },
239
- buildOutputDirs: [".expo", "dist"],
240
- platformSuffixes: ["ios", "android", "native", "web"],
241
- routerDirs: []
242
- };
243
- var EXPO = { ...EXPO_ROUTER, layerDirs: {} };
244
- var GENERIC = {
245
- id: "generic",
246
- recognised: false,
247
- layers: ALL_LAYERS,
248
- layerDirs: {},
249
- buildOutputDirs: ["dist", "build"],
250
- platformSuffixes: [],
251
- routerDirs: []
252
- };
253
- var PROFILES = { next: NEXT, "react-vite": REACT_VITE, expo: EXPO_ROUTER, generic: GENERIC };
254
- function profileById(id) {
255
- return PROFILES[id];
256
- }
257
- var NEXT_CONFIGS = ["next.config.js", "next.config.mjs", "next.config.ts", "next.config.cjs"];
258
- var VITE_CONFIGS = ["vite.config.ts", "vite.config.mts", "vite.config.js", "vite.config.mjs"];
259
- var EXPO_CONFIGS = ["app.config.ts", "app.config.js", "app.config.mjs"];
260
- function hasExpoKey(input, file) {
261
- const text = input.read(file);
262
- if (typeof text !== "string")
263
- return false;
264
- try {
265
- return typeof JSON.parse(text)["expo"] === "object";
266
- } catch {
267
- return false;
268
- }
269
- }
270
- function dependsOn(input, manifest, name) {
271
- const text = input.read(manifest);
272
- if (typeof text !== "string")
273
- return false;
274
- try {
275
- const parsed = JSON.parse(text);
276
- return ["dependencies", "devDependencies", "peerDependencies"].some((field) => parsed[field]?.[name] !== void 0);
277
- } catch {
278
- return false;
279
- }
280
- }
281
- function detectFramework(input) {
282
- const prefix = input.projectRoot === "" || input.projectRoot === "." ? "" : `${input.projectRoot}/`;
283
- const executors = input.executors ?? [];
284
- if (NEXT_CONFIGS.some((file) => input.exists(`${prefix}${file}`)) || executors.some((executor) => executor.startsWith("@nx/next:"))) {
285
- return NEXT;
286
- }
287
- const dependsAnywhere = (name) => dependsOn(input, `${prefix}package.json`, name) || dependsOn(input, "package.json", name);
288
- 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");
289
- if (usesExpo)
290
- return dependsAnywhere("expo-router") ? EXPO_ROUTER : EXPO;
291
- const usesReact = dependsAnywhere("react");
292
- const usesVite = VITE_CONFIGS.some((file) => input.exists(`${prefix}${file}`)) || executors.some((executor) => executor.startsWith("@nx/vite:"));
293
- if (usesVite && usesReact)
294
- return REACT_VITE;
295
- return GENERIC;
296
- }
297
-
298
- // ../template-engine/dist/fsd/fsd-eslint-config.js
299
- function classifyFsdEslintConfig(configText) {
300
- return maskComments(configText).includes(FSD_ESLINT_MODULE) ? "applied" : "absent";
301
- }
302
- var EXPORT_DEFAULT_ARRAY = /export\s+default\s+\[/g;
303
- var IMPORT_STATEMENT = /^import\b[^;]*?\bfrom\s+['"][^'"]+['"]\s*;?[ \t]*$/gm;
304
- var CLOSING_BRACKET = /\]\s*;?\s*$/;
305
- function closingBracketOf(masked, open) {
306
- let depth = 0;
307
- for (let i = open; i < masked.length; i++) {
308
- const ch = masked[i];
309
- if (ch === '"' || ch === "'" || ch === "`") {
310
- for (i++; i < masked.length && masked[i] !== ch; i++)
311
- if (masked[i] === "\\")
312
- i++;
313
- continue;
314
- }
315
- if (ch === "[")
316
- depth++;
317
- else if (ch === "]" && --depth === 0)
318
- return i;
319
- }
320
- return -1;
321
- }
322
- function namedConfigArrayEnd(masked) {
323
- const exported = [...masked.matchAll(/export\s+default\s+([A-Za-z_$][\w$]*)\s*;?/g)];
324
- if (exported.length !== 1)
325
- return -1;
326
- const declaration = new RegExp(`(?:const|let|var)\\s+${exported[0][1].replace(/\$/g, "\\$")}\\s*=\\s*(?:defineConfig\\s*\\(\\s*)?\\[`).exec(masked);
327
- if (declaration === null)
328
- return -1;
329
- return closingBracketOf(masked, declaration.index + declaration[0].length - 1);
330
- }
331
- function applyFsdEslintConfig(configText, severity, root = "src", framework = {}) {
332
- if (classifyFsdEslintConfig(configText) === "applied")
333
- return { status: "already-applied" };
334
- const masked = maskComments(configText);
335
- EXPORT_DEFAULT_ARRAY.lastIndex = 0;
336
- const exportMatches = masked.match(EXPORT_DEFAULT_ARRAY) ?? [];
337
- const closing = CLOSING_BRACKET.exec(masked);
338
- const closingIndex = exportMatches.length === 1 && closing !== null ? closing.index : namedConfigArrayEnd(masked);
339
- if (closingIndex === -1)
340
- return { status: "unrecognized" };
341
- const eol = configText.includes("\r\n") ? "\r\n" : "\n";
342
- const before = configText.slice(0, closingIndex);
343
- const lastNonSpace = before.replace(/\s+$/, "");
344
- const needsComma = !lastNonSpace.endsWith(",") && !lastNonSpace.endsWith("[");
345
- const entryText = `${needsComma ? "," : ""}${eol} ${buildFsdEslintEntry(severity, root, framework)}${eol}`;
346
- const withEntry = `${lastNonSpace}${entryText}${configText.slice(closingIndex)}`;
347
- IMPORT_STATEMENT.lastIndex = 0;
348
- let lastImportEnd = -1;
349
- const maskedWithEntry = maskComments(withEntry);
350
- for (let m = IMPORT_STATEMENT.exec(maskedWithEntry); m !== null; m = IMPORT_STATEMENT.exec(maskedWithEntry)) {
351
- lastImportEnd = m.index + m[0].length;
352
- }
353
- const importLine = buildFsdEslintImportLine();
354
- const text = lastImportEnd === -1 ? `${importLine}${eol}${eol}${withEntry}` : `${withEntry.slice(0, lastImportEnd)}${eol}${importLine}${withEntry.slice(lastImportEnd)}`;
355
- return { status: "applied", text };
356
- }
357
- function buildFsdEslintPasteSnippet(severity, locale, root = "src", framework = {}) {
358
- return buildFsdEslintSnippet({ severity, locale, root, framework });
359
- }
360
- function composeFsdLayerGuide({ profile, sourceRoot, locale }) {
361
- const layers = [...profile.layers];
362
- return buildFsdLayerGuide({ layers, directories: layers.map((layer) => profile.layerDirs[layer] ?? layer), sourceRoot, locale });
363
- }
364
-
365
- // src/generators/shared/dry-run.ts
366
- function resolveDryRun(options) {
367
- return process.env["NX_DRY_RUN"] === "true" || (options.dryRun ?? false);
368
- }
369
-
370
- // src/generators/shared/frontend-app.ts
371
- import { getProjects } from "@nx/devkit";
372
-
373
- // src/generators/shared/json-edit.ts
374
- import { findNodeAtLocation, parseTree } from "jsonc-parser";
375
- function detectIndent(raw) {
376
- for (const line of raw.split("\n")) {
377
- const match = /^(\t+| +)/.exec(line);
378
- if (match) return match[1];
379
- }
380
- return " ";
381
- }
382
- function styleOf(raw) {
383
- return { eol: raw.includes("\r\n") ? "\r\n" : "\n", unit: detectIndent(raw) };
384
- }
385
- function lineIndentAt(raw, offset) {
386
- const lineStart = raw.lastIndexOf("\n", offset - 1) + 1;
387
- return /^[ \t]*/.exec(raw.slice(lineStart))?.[0] ?? "";
388
- }
389
- function isMultiline(raw, node) {
390
- return raw.slice(node.offset, node.offset + node.length).includes("\n");
391
- }
392
- function isPrimitive(value) {
393
- return value === null || ["string", "number", "boolean"].includes(typeof value);
394
- }
395
- function renderValue(value, indent, style) {
396
- if (isPrimitive(value)) return JSON.stringify(value);
397
- if (Array.isArray(value)) {
398
- if (value.every(isPrimitive)) return `[${value.map((item) => JSON.stringify(item)).join(", ")}]`;
399
- const inner2 = `${indent}${style.unit}`;
400
- return `[${style.eol}${value.map((item) => `${inner2}${renderValue(item, inner2, style)}`).join(`,${style.eol}`)}${style.eol}${indent}]`;
401
- }
402
- const entries = Object.entries(value);
403
- if (entries.length === 0) return "{}";
404
- const inner = `${indent}${style.unit}`;
405
- const body = entries.map(([key, item]) => `${inner}${JSON.stringify(key)}: ${renderValue(item, inner, style)}`).join(`,${style.eol}`);
406
- return `{${style.eol}${body}${style.eol}${indent}}`;
407
- }
408
- function splice(raw, start, end, text) {
409
- return raw.slice(0, start) + text + raw.slice(end);
410
- }
411
- function nest(keys, value) {
412
- return keys.reduceRight((inner, key) => ({ [key]: inner }), value);
413
- }
414
- function insertProperty(raw, object, key, value, style) {
415
- const properties = object.children ?? [];
416
- const objectIndent = lineIndentAt(raw, object.offset);
417
- if (properties.length === 0) {
418
- const inner = `${objectIndent}${style.unit}`;
419
- const text = `{${style.eol}${inner}${JSON.stringify(String(key))}: ${renderValue(value, inner, style)}${style.eol}${objectIndent}}`;
420
- return splice(raw, object.offset, object.offset + object.length, text);
421
- }
422
- const last = properties[properties.length - 1];
423
- const end = last.offset + last.length;
424
- if (!isMultiline(raw, object)) {
425
- return splice(raw, end, end, `, ${JSON.stringify(String(key))}: ${renderValue(value, "", style)}`);
426
- }
427
- const indent = lineIndentAt(raw, last.offset);
428
- return splice(raw, end, end, `,${style.eol}${indent}${JSON.stringify(String(key))}: ${renderValue(value, indent, style)}`);
429
- }
430
- function setJsonValue(raw, path, value) {
431
- const style = styleOf(raw);
432
- const root = parseTree(raw);
433
- if (root === void 0) throw new Error("setJsonValue: not a JSON document");
434
- const existing = findNodeAtLocation(root, path);
435
- if (existing !== void 0) {
436
- return splice(raw, existing.offset, existing.offset + existing.length, renderValue(value, lineIndentAt(raw, existing.offset), style));
437
- }
438
- for (let depth = path.length - 1; depth >= 0; depth--) {
439
- const parent = depth === 0 ? root : findNodeAtLocation(root, path.slice(0, depth));
440
- if (parent === void 0) continue;
441
- if (parent.type !== "object") throw new Error(`setJsonValue: ${path.slice(0, depth).join(".") || "the root"} is not an object`);
442
- return insertProperty(raw, parent, path[depth], nest(path.slice(depth + 1), value), style);
443
- }
444
- throw new Error("setJsonValue: unreachable");
445
- }
446
- function applyJsonEdits(raw, edits) {
447
- if (raw === null) {
448
- let text = "{}\n";
449
- for (const [path, value] of edits) text = setJsonValue(text, path, value);
450
- return text;
451
- }
452
- return edits.reduce((text, [path, value]) => setJsonValue(text, path, value), raw);
453
- }
454
-
455
- // src/generators/shared/toolkit-config-file.ts
456
- var TOOLKIT_CONFIG_PATH = "toolkit.config.json";
457
- function readToolkitConfigFile(tree) {
458
- const raw = tree.read(TOOLKIT_CONFIG_PATH, "utf-8");
459
- if (raw === null) return { raw: null, parsed: null };
460
- try {
461
- const parsed = JSON.parse(raw);
462
- return {
463
- raw,
464
- parsed: typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : null
465
- };
466
- } catch {
467
- return { raw, parsed: null };
468
- }
469
- }
470
- function readToolkitConfig(tree) {
471
- return readToolkitConfigFile(tree).parsed;
472
- }
473
- function resolveLocaleOption(option, config) {
474
- if (option) return option;
475
- const locale = config?.["locale"];
476
- return locale === "ko" || locale === "en" ? locale : "en";
477
- }
478
- function recordedChoice(config, key, allowed) {
479
- const value = config?.[key];
480
- return typeof value === "string" && allowed.includes(value) ? value : void 0;
481
- }
482
- var RECORDED_FRONTENDS = ["react-vite", "next", "expo", "generic", "none"];
483
- var RECORDED_PACKAGE_MANAGERS = ["pnpm", "npm", "yarn", "bun"];
484
- function resolveFrontendOption(option, config, generator) {
485
- const frontend = option ?? recordedChoice(config, "frontend", RECORDED_FRONTENDS);
486
- if (frontend === void 0) {
487
- throw new Error(`${generator}: pass --frontend=react-vite|next|expo|generic (toolkit.config.json records none \u2014 init writes it).`);
488
- }
489
- if (frontend === "none") {
490
- throw new Error(
491
- `${generator}: this is a backend-only workspace (toolkit.config.json frontend: none) \u2014 FSD structures a frontend app. Pass --frontend=react-vite|next|expo|generic if you added one.`
492
- );
493
- }
494
- return frontend;
495
- }
496
- function workspacePackageManager(exists, read, config) {
497
- return detectWorkspacePackageManager(exists, read) ?? recordedChoice(config, "packageManager", RECORDED_PACKAGE_MANAGERS) ?? null;
498
- }
499
- function treePackageManager(tree, config) {
500
- return workspacePackageManager((p) => tree.exists(p), (p) => tree.read(p, "utf-8"), config);
501
- }
502
-
503
- // src/generators/shared/project-type.ts
504
- import { parseJson } from "@nx/devkit";
505
- function resolveProjectType(tree, root, declared) {
506
- if (declared) return declared === "library" ? "library" : "application";
507
- const prefix = root === "" || root === "." ? "" : `${root}/`;
508
- if (tree.exists(`${prefix}tsconfig.lib.json`)) return "library";
509
- if (tree.exists(`${prefix}tsconfig.app.json`)) return "application";
510
- const raw = tree.read(`${prefix}package.json`, "utf-8");
511
- if (raw === null) return "library";
512
- try {
513
- const manifest = parseJson(raw);
514
- if (manifest && !["exports", "main", "module", "bin"].some((key) => Boolean(manifest[key]))) return "application";
515
- } catch {
516
- }
517
- return "library";
518
- }
519
-
520
- // src/generators/shared/frontend-app.ts
521
- var baseNameOf = (root) => root.split("/").pop() ?? root;
522
- function isEndToEnd(root) {
523
- const dir = baseNameOf(root);
524
- return dir === "e2e" || dir.endsWith("-e2e");
525
- }
526
- function isBackend(root, config, backendTag) {
527
- return baseNameOf(root) === "api" || (config.tags ?? []).includes(backendTag);
528
- }
529
- function prefixOf(root) {
530
- return root === "" || root === "." ? "" : `${root}/`;
531
- }
532
- function sourceRootOf(tree, config) {
533
- const prefix = prefixOf(config.root);
534
- const declared = config.sourceRoot?.replace(/\/$/, "");
535
- const atRoot = declared !== void 0 && (declared === config.root || prefix === "" && (declared === "." || declared === ""));
536
- if (declared && !atRoot) return declared;
537
- if (atRoot && !tree.exists(`${prefix}src`)) return prefix === "" ? "." : config.root;
538
- return `${prefix}src`;
539
- }
540
- function frameworkOf(tree, config) {
541
- return detectFramework({
542
- exists: (path) => tree.exists(path),
543
- read: (path) => tree.read(path, "utf-8"),
544
- projectRoot: config.root,
545
- executors: Object.values(config.targets ?? {}).flatMap((target) => target.executor ? [target.executor] : [])
546
- });
547
- }
548
- function resolveFrontendApp(tree, explicitProject) {
549
- let projects;
550
- try {
551
- projects = getProjects(tree);
552
- } catch (error) {
553
- const message = error instanceof Error ? error.message : String(error);
554
- const pathMatch = /Cannot parse ([^:]+):/.exec(message);
555
- return { kind: "invalid-project-json", detail: pathMatch ? pathMatch[1] : message };
556
- }
557
- const found = (project2, config2) => {
558
- const profile = frameworkOf(tree, config2);
559
- return { kind: "found", project: project2, root: config2.root, sourceRoot: sourceRootOf(tree, config2), framework: profile.id, profile };
560
- };
561
- if (explicitProject !== void 0) {
562
- const config2 = projects.get(explicitProject);
563
- if (config2) return found(explicitProject, config2);
564
- const rootApp = inferredRootApp(tree, projects);
565
- return rootApp?.kind === "found" && rootApp.project === explicitProject ? rootApp : { kind: "not-found", project: explicitProject };
566
- }
567
- const backendTag = readBoundaryTags(readToolkitConfig(tree)).backend;
568
- const eligible = [...projects.entries()].filter(([, config2]) => !isEndToEnd(config2.root) && !isBackend(config2.root, config2, backendTag));
569
- const declared = eligible.filter(([, config2]) => config2.projectType === "application");
570
- const inferred = eligible.filter(([, config2]) => {
571
- if (config2.projectType !== void 0) return false;
572
- if (config2.root === "" || config2.root === ".") return frameworkOf(tree, config2).recognised;
573
- return resolveProjectType(tree, config2.root, void 0) === "application";
574
- });
575
- const candidates = (declared.length > 0 ? declared : inferred).sort(([a], [b]) => a.localeCompare(b));
576
- if (candidates.length === 0) {
577
- const rootApp = inferredRootApp(tree, projects);
578
- if (rootApp !== null) return rootApp;
579
- const otherProjects = [...projects.keys()].filter((name) => !isEndToEnd(projects.get(name)?.root ?? "")).sort();
580
- return { kind: "none", otherProjects };
581
- }
582
- if (candidates.length > 1) return { kind: "ambiguous", candidates: candidates.map(([name]) => name) };
583
- const [project, config] = candidates[0];
584
- return found(project, config);
585
- }
586
- function inferredRootApp(tree, projects) {
587
- if ([...projects.values()].some((config2) => config2.root === "" || config2.root === ".")) return null;
588
- const raw = tree.read("package.json", "utf-8");
589
- if (raw === null) return null;
590
- let name;
591
- try {
592
- name = JSON.parse(raw).name;
593
- } catch {
594
- return null;
595
- }
596
- if (typeof name !== "string" || name === "") return null;
597
- const config = { name, root: "." };
598
- const framework = frameworkOf(tree, config);
599
- if (!framework.recognised) return null;
600
- return { kind: "found", project: name, root: ".", sourceRoot: sourceRootOf(tree, config), framework: framework.id, profile: framework, inferredRoot: true };
601
- }
602
-
603
- // src/generators/add-fsd-lite/render.ts
604
- function renderAddFsdLiteReport(report) {
605
- const lines = [];
606
- if (report.aborted) {
607
- lines.push("add-fsd-lite aborted \u2014 nothing was written.");
608
- const refusal = report.appRefusal;
609
- if (refusal !== null) {
610
- lines.push("");
611
- lines.push(" FSD layers live inside the frontend app's source root (e.g. apps/web/src), and no app could be picked:");
612
- if (refusal.reason === "project-not-found") {
613
- lines.push(` --project=${refusal.project} names no project in this workspace.`);
614
- } else if (refusal.reason === "ambiguous-frontend") {
615
- lines.push(" more than one frontend app was found \u2014 rerun with --project=<one of them>:");
616
- for (const name of refusal.candidates) lines.push(` - ${name}`);
617
- } else if (refusal.reason === "invalid-project-json") {
618
- lines.push(` a project.json could not be parsed (${refusal.detail}) \u2014 fix it, then rerun.`);
619
- } else if (refusal.otherProjects.length > 0) {
620
- lines.push(" no project was recognised as a frontend app. If one of these is it, rerun with --project=<name>:");
621
- for (const name of refusal.otherProjects) lines.push(` - ${name}`);
622
- } else {
623
- lines.push(" the workspace has no projects \u2014 create one (e.g. nx g @nx/react:app or nx g @nx/next:app), then rerun.");
624
- }
625
- }
626
- return lines.join("\n");
627
- }
628
- if (report.dryRun) {
629
- lines.push("add-fsd-lite dry-run \u2014 no files were written.");
630
- lines.push("");
631
- }
632
- lines.push(`FSD layers (in ${report.project}, ${report.sourceRoot}):`);
633
- if (report.layerGuide !== null && report.frontend === "generic") {
634
- lines.push("Frontend: framework not recognised \u2014 the common FSD rules apply, with no framework-specific layer names.");
635
- }
636
- if (report.layerGuide !== null) lines.push(report.layerGuide);
637
- lines.push("");
638
- const where = report.eslintPath ?? `${report.project}'s eslint.config.mjs`;
639
- switch (report.eslint) {
640
- case "applied":
641
- lines.push(`ESLint: archweave/fsd-boundaries (${report.enforcement}) written to ${where}`);
642
- break;
643
- case "already-applied":
644
- lines.push(`ESLint: archweave/fsd-boundaries already wired in ${where} \u2014 no change`);
645
- break;
646
- case "degraded-unrecognized":
647
- lines.push(`ESLint: ${report.eslintPath === null ? `no ESLint config found for ${report.project}` : `${where} was NOT recognized \u2014 left untouched`}.`);
648
- lines.push(" Add the rule yourself (then the layer rules are actually enforced):");
649
- break;
650
- case "snippet-only":
651
- lines.push(`ESLint: report-only (pass --applyEslint to write the rule into ${where}).`);
652
- break;
653
- case "not-applied":
654
- break;
655
- }
656
- if (report.snippet !== null) lines.push(report.snippet);
657
- if (report.steiger !== null) {
658
- const st = report.steiger;
659
- lines.push("");
660
- lines.push("steiger (official FSD linter, opt-in):");
661
- lines.push(
662
- ` ${st.configPath}: ${st.config === "created" ? "created" : st.config === "unchanged" ? "unchanged" : "kept \u2014 an existing config with other content is never replaced"}`
663
- );
664
- lines.push(
665
- st.target === "added" ? ` target ${"fsd-check"}: added to ${st.targetPath}` : st.target === "present" ? ` target ${"fsd-check"}: already present in ${st.targetPath}` : " target fsd-check: NOT added \u2014 no parseable project.json / package.json for the app"
666
- );
667
- lines.push(
668
- st.dependencies === "added" ? ` devDependencies: steiger + @feature-sliced/steiger-plugin added to package.json \u2014 run \`${st.installCommand}\`` : st.dependencies === "present" ? " devDependencies: already present" : " devDependencies: NOT added \u2014 the root package.json could not be parsed"
669
- );
670
- lines.push(` run it with: ${st.runCommand} (steiger needs Node >= 22.18)`);
671
- }
672
- return lines.join("\n");
673
- }
674
-
675
- // src/generators/add-fsd-lite/generator.ts
676
- function resolveEnforcement(option, config) {
677
- if (option === "error" || option === "warn") return option;
678
- return readFsdEnforcement(config?.["fsd"]) ?? "warn";
679
- }
680
- function runAddFsdLite(tree, options) {
681
- const config = readToolkitConfig(tree);
682
- const locale = resolveLocaleOption(options.locale, config);
683
- const enforcement = resolveEnforcement(options.enforcement, config);
684
- const frontend = resolveFrontendOption(options.frontend, config, "add-fsd-lite");
685
- const dryRun = options.dryRun ?? false;
686
- const applyEslint = options.applyEslint ?? false;
687
- const app = resolveFrontendApp(tree, options.project);
688
- if (app.kind !== "found") {
689
- const snippet2 = buildFsdEslintPasteSnippet(enforcement, locale);
690
- const appRefusal = app.kind === "not-found" ? { reason: "project-not-found", project: app.project } : app.kind === "ambiguous" ? { reason: "ambiguous-frontend", candidates: app.candidates } : app.kind === "invalid-project-json" ? { reason: "invalid-project-json", detail: app.detail } : { reason: "no-frontend-app", otherProjects: app.otherProjects };
691
- return { dryRun, aborted: true, appRefusal, project: null, sourceRoot: null, enforcement, frontend, eslint: "not-applied", eslintPath: null, snippet: snippet2, layerGuide: null, steiger: null };
692
- }
693
- const appDir = app.root === "" || app.root === "." ? "" : `${app.root}/`;
694
- const eslintRoot = posix.relative(app.root === "" ? "." : app.root, app.sourceRoot) || ".";
695
- const profile = app.framework === frontend ? app.profile : profileById(frontend);
696
- const { platformSuffixes, routerDirs } = profile;
697
- const framework = { platformSuffixes, routerDirs };
698
- const snippet = buildFsdEslintPasteSnippet(enforcement, locale, eslintRoot, framework);
699
- const eslintPath = ESLINT_CONFIG_CANDIDATES.map((name) => `${appDir}${name}`).find((path) => tree.exists(path)) ?? null;
700
- const configText = eslintPath === null ? null : tree.read(eslintPath, "utf-8");
701
- let eslint;
702
- if (!applyEslint) {
703
- eslint = configText !== null && applyFsdEslintConfig(configText, enforcement, eslintRoot, framework).status === "already-applied" ? "already-applied" : "snippet-only";
704
- } else if (configText === null) {
705
- eslint = "degraded-unrecognized";
706
- } else {
707
- const result = applyFsdEslintConfig(configText, enforcement, eslintRoot, framework);
708
- eslint = result.status === "applied" ? "applied" : result.status === "already-applied" ? "already-applied" : "degraded-unrecognized";
709
- if (result.status === "applied" && !dryRun && eslintPath !== null) tree.write(eslintPath, result.text);
710
- }
711
- const steiger = options.steiger ? addSteiger(tree, { appDir, appRoot: app.root, sourceRoot: app.sourceRoot, profile, locale, write: !dryRun, config }) : null;
712
- return {
713
- dryRun,
714
- aborted: false,
715
- appRefusal: null,
716
- project: app.project,
717
- sourceRoot: app.sourceRoot,
718
- steiger,
719
- enforcement,
720
- frontend,
721
- eslint,
722
- eslintPath,
723
- snippet: eslint === "applied" || eslint === "already-applied" ? null : snippet,
724
- layerGuide: composeFsdLayerGuide({ profile, sourceRoot: app.sourceRoot, locale })
725
- };
726
- }
727
- function readJsonObject(tree, path) {
728
- const raw = tree.read(path, "utf-8");
729
- if (raw === null) return null;
730
- try {
731
- const parsed = JSON.parse(raw);
732
- return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? { raw, parsed } : null;
733
- } catch {
734
- return null;
735
- }
736
- }
737
- function addSteiger(tree, input) {
738
- const configPath = `${input.appDir}${STEIGER_CONFIG_FILE}`;
739
- const configText = buildSteigerConfig({ renamedLayerDirs: Object.values(input.profile.layerDirs), locale: input.locale });
740
- const existing = tree.read(configPath, "utf-8");
741
- let configAction;
742
- if (existing === null) {
743
- configAction = "created";
744
- if (input.write) tree.write(configPath, configText);
745
- } else {
746
- configAction = existing === configText ? "unchanged" : "kept";
747
- }
748
- const rootPrefix = input.appRoot === "" || input.appRoot === "." ? "" : `${input.appRoot}/`;
749
- const sourceRootName = input.sourceRoot.startsWith(rootPrefix) ? input.sourceRoot.slice(rootPrefix.length) : "src";
750
- const target = buildFsdCheckTarget(sourceRootName);
751
- let targetAction = "unrecognized";
752
- let targetPath = null;
753
- for (const candidate of [`${input.appDir}project.json`, `${input.appDir}package.json`]) {
754
- const file = readJsonObject(tree, candidate);
755
- if (file === null) continue;
756
- targetPath = candidate;
757
- const holder = candidate.endsWith("project.json") ? file.parsed : file.parsed["nx"] ??= {};
758
- if (typeof holder !== "object" || holder === null) break;
759
- const targets = holder["targets"] ??= {};
760
- if (typeof targets !== "object" || targets === null) break;
761
- if (targets[FSD_CHECK_TARGET] !== void 0) {
762
- targetAction = "present";
763
- } else {
764
- targets[FSD_CHECK_TARGET] = target;
765
- targetAction = "added";
766
- const path = candidate.endsWith("project.json") ? ["targets", FSD_CHECK_TARGET] : ["nx", "targets", FSD_CHECK_TARGET];
767
- if (input.write) tree.write(candidate, setJsonValue(file.raw, path, target));
768
- }
769
- break;
770
- }
771
- let dependenciesAction = "unrecognized";
772
- const rootPackage = readJsonObject(tree, "package.json");
773
- if (rootPackage !== null) {
774
- const devDependencies = rootPackage.parsed["devDependencies"] ??= {};
775
- const dependencies = rootPackage.parsed["dependencies"] ?? {};
776
- const missing = Object.entries(STEIGER_DEPENDENCIES).filter(([name]) => devDependencies[name] === void 0 && dependencies[name] === void 0);
777
- if (missing.length === 0) {
778
- dependenciesAction = "present";
779
- } else {
780
- for (const [name, range] of missing) devDependencies[name] = range;
781
- dependenciesAction = "added";
782
- const edited = applyJsonEdits(rootPackage.raw, missing.map(([name, range]) => [["devDependencies", name], range]));
783
- if (input.write) tree.write("package.json", edited);
784
- }
785
- }
786
- const pm = treePackageManager(tree, input.config) ?? "pnpm";
787
- const commands = packageManagerCommands(pm, pm === "yarn" ? detectYarnFlavor((p) => tree.exists(p), (p) => tree.read(p, "utf-8")) : void 0);
788
- return {
789
- configPath,
790
- config: configAction,
791
- targetPath,
792
- target: targetAction,
793
- dependencies: dependenciesAction,
794
- installCommand: commands.install,
795
- runCommand: `${commands.runNx} run <project>:${FSD_CHECK_TARGET}`
796
- };
797
- }
798
- async function addFsdLiteGenerator(tree, options) {
799
- console.log(renderAddFsdLiteReport(runAddFsdLite(tree, { ...options, dryRun: resolveDryRun(options) })));
800
- }
801
- var generator_default = addFsdLiteGenerator;
1
+ import {
2
+ addFsdLiteGenerator,
3
+ generator_default,
4
+ runAddFsdLite
5
+ } from "../_chunks/chunk-YY2UESLM.js";
6
+ import "../_chunks/chunk-L2RZ2LBO.js";
7
+ import "../_chunks/chunk-2WSX5YNB.js";
8
+ import "../_chunks/chunk-TXAQ2GJC.js";
9
+ import "../_chunks/chunk-6ZTIUBB2.js";
10
+ import "../_chunks/chunk-TUN34LAQ.js";
11
+ import "../_chunks/chunk-EXYZLL7A.js";
12
+ import "../_chunks/chunk-FQHFT5IH.js";
802
13
  export {
803
14
  addFsdLiteGenerator,
804
15
  generator_default as default,