@clearlydev/nx-archweave 0.0.0-stage → 0.1.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +265 -2
  3. package/dist/bin/review-verdict.js +330 -0
  4. package/dist/eslint/fsd-boundaries.d.ts +119 -0
  5. package/dist/eslint/fsd-boundaries.js +144 -0
  6. package/dist/eslint/index.d.ts +78 -0
  7. package/dist/eslint/index.js +256 -0
  8. package/dist/eslint/tsconfig-aliases.d.ts +18 -0
  9. package/dist/eslint/tsconfig-aliases.js +114 -0
  10. package/dist/generators/add-agent-rules/generator.js +550 -0
  11. package/dist/generators/add-agent-rules/render.js +46 -0
  12. package/dist/generators/add-backend/generator.js +784 -0
  13. package/dist/generators/add-backend/render.js +102 -0
  14. package/dist/generators/add-fsd-lite/generator.js +553 -0
  15. package/dist/generators/add-fsd-lite/render.js +72 -0
  16. package/dist/generators/add-github-templates/files/en/codeowners/.github/CODEOWNERS.template +4 -0
  17. package/dist/generators/add-github-templates/files/en/issue/.github/ISSUE_TEMPLATE/bug-report.yml.template +28 -0
  18. package/dist/generators/add-github-templates/files/en/issue/.github/ISSUE_TEMPLATE/feature-request.yml.template +17 -0
  19. package/dist/generators/add-github-templates/files/en/pr/.github/PULL_REQUEST_TEMPLATE.md.template +12 -0
  20. package/dist/generators/add-github-templates/files/ko/codeowners/.github/CODEOWNERS.template +4 -0
  21. package/dist/generators/add-github-templates/files/ko/issue/.github/ISSUE_TEMPLATE/bug-report.yml.template +28 -0
  22. package/dist/generators/add-github-templates/files/ko/issue/.github/ISSUE_TEMPLATE/feature-request.yml.template +17 -0
  23. package/dist/generators/add-github-templates/files/ko/pr/.github/PULL_REQUEST_TEMPLATE.md.template +12 -0
  24. package/dist/generators/add-github-templates/generator.js +125 -0
  25. package/dist/generators/add-github-templates/render.js +26 -0
  26. package/dist/generators/add-integration/generator.js +849 -0
  27. package/dist/generators/add-integration/render.js +34 -0
  28. package/dist/generators/add-review/generator.js +921 -0
  29. package/dist/generators/add-review/render.js +96 -0
  30. package/dist/generators/allow-builds/generator.js +436 -0
  31. package/dist/generators/allow-builds/render.js +82 -0
  32. package/dist/generators/doctor/generator.js +2462 -0
  33. package/dist/generators/doctor/integration-report.js +70 -0
  34. package/dist/generators/doctor/render.js +10 -0
  35. package/dist/generators/entity/generator.js +395 -0
  36. package/dist/generators/feature/generator.js +395 -0
  37. package/dist/generators/init/generator.js +3211 -0
  38. package/dist/generators/init/render.js +125 -0
  39. package/dist/generators/init/validation.js +74 -0
  40. package/dist/generators/install-integration/generator.js +1265 -0
  41. package/dist/generators/install-integration/render.js +128 -0
  42. package/dist/generators/page/generator.js +395 -0
  43. package/dist/generators/record-integration/generator.js +883 -0
  44. package/dist/generators/record-integration/render.js +31 -0
  45. package/dist/generators/shared/dry-run.js +12 -0
  46. package/dist/generators/shared/frontend-app.js +57 -0
  47. package/dist/generators/shared/generator.js +395 -0
  48. package/dist/generators/shared/project-type.js +39 -0
  49. package/dist/generators/shared/record-pipeline.js +34 -0
  50. package/dist/generators/shared/run-nx.js +24 -0
  51. package/dist/generators/shared/template-files.js +38 -0
  52. package/dist/generators/shared/toolkit-config-file.js +110 -0
  53. package/dist/generators/slice/core.js +185 -0
  54. package/dist/generators/slice/files/index/index.ts.template +14 -0
  55. package/dist/generators/slice/files/module/__name__.spec.ts.template +11 -0
  56. package/dist/generators/slice/files/module/__name__.ts.template +11 -0
  57. package/dist/generators/slice/files/segment/index.ts.template +20 -0
  58. package/dist/generators/slice/render.js +70 -0
  59. package/dist/generators/widget/generator.js +395 -0
  60. package/dist/index.d.ts +2 -0
  61. package/dist/index.js +711 -0
  62. package/dist/lib/nx-plugin.d.ts +2 -0
  63. package/dist/lib/nx-plugin.js +7 -0
  64. package/dist/runtime/integrations-composition-root.js +20 -0
  65. package/dist/runtime/node-command-runner.js +81 -0
  66. package/generators.json +85 -0
  67. package/package.json +96 -4
  68. package/src/generators/add-agent-rules/schema.json +43 -0
  69. package/src/generators/add-backend/schema.json +39 -0
  70. package/src/generators/add-fsd-lite/schema.json +43 -0
  71. package/src/generators/add-github-templates/schema.json +35 -0
  72. package/src/generators/add-integration/schema.json +35 -0
  73. package/src/generators/add-review/schema.json +72 -0
  74. package/src/generators/allow-builds/schema.json +20 -0
  75. package/src/generators/doctor/schema.json +20 -0
  76. package/src/generators/entity/schema.json +37 -0
  77. package/src/generators/feature/schema.json +37 -0
  78. package/src/generators/init/schema.json +98 -0
  79. package/src/generators/install-integration/schema.json +35 -0
  80. package/src/generators/page/schema.json +53 -0
  81. package/src/generators/record-integration/schema.json +26 -0
  82. package/src/generators/shared/schema.json +32 -0
  83. package/src/generators/widget/schema.json +45 -0
@@ -0,0 +1,72 @@
1
+ export function renderAddFsdLiteReport(report) {
2
+ const lines = [];
3
+ if (report.aborted) {
4
+ lines.push('add-fsd-lite aborted — nothing was written.');
5
+ const refusal = report.appRefusal;
6
+ if (refusal !== null) {
7
+ lines.push('');
8
+ lines.push(" FSD layers live inside the frontend app's source root (e.g. apps/web/src), and no app could be picked:");
9
+ if (refusal.reason === 'project-not-found') {
10
+ lines.push(` --project=${refusal.project} names no project in this workspace.`);
11
+ }
12
+ else if (refusal.reason === 'ambiguous-frontend') {
13
+ lines.push(' more than one frontend app was found — rerun with --project=<one of them>:');
14
+ for (const name of refusal.candidates)
15
+ lines.push(` - ${name}`);
16
+ }
17
+ else if (refusal.reason === 'invalid-project-json') {
18
+ lines.push(` a project.json could not be parsed (${refusal.detail}) — fix it, then rerun.`);
19
+ }
20
+ else {
21
+ lines.push(' the workspace has no frontend application — create one (e.g. nx g @nx/react:app) or pass --project.');
22
+ }
23
+ }
24
+ return lines.join('\n');
25
+ }
26
+ if (report.dryRun) {
27
+ lines.push('add-fsd-lite dry-run — no files were written.');
28
+ lines.push('');
29
+ }
30
+ lines.push(`FSD layers (in ${report.project}, ${report.sourceRoot}):`);
31
+ if (report.layerGuide !== null)
32
+ lines.push(report.layerGuide);
33
+ lines.push('');
34
+ const where = report.eslintPath ?? `${report.project}'s eslint.config.mjs`;
35
+ switch (report.eslint) {
36
+ case 'applied':
37
+ lines.push(`ESLint: archweave/fsd-boundaries (${report.enforcement}) written to ${where}`);
38
+ break;
39
+ case 'already-applied':
40
+ lines.push(`ESLint: archweave/fsd-boundaries already wired in ${where} — no change`);
41
+ break;
42
+ case 'degraded-unrecognized':
43
+ lines.push(`ESLint: ${report.eslintPath === null ? `no ESLint config found for ${report.project}` : `${where} was NOT recognized — left untouched`}.`);
44
+ lines.push(' Add the rule yourself (then the layer rules are actually enforced):');
45
+ break;
46
+ case 'snippet-only':
47
+ lines.push(`ESLint: report-only (pass --applyEslint to write the rule into ${where}).`);
48
+ break;
49
+ case 'not-applied':
50
+ break;
51
+ }
52
+ if (report.snippet !== null)
53
+ lines.push(report.snippet);
54
+ if (report.steiger !== null) {
55
+ const st = report.steiger;
56
+ lines.push('');
57
+ lines.push('steiger (official FSD linter, opt-in):');
58
+ lines.push(` ${st.configPath}: ${st.config === 'created' ? 'created' : st.config === 'unchanged' ? 'unchanged' : 'kept — an existing config with other content is never replaced'}`);
59
+ lines.push(st.target === 'added'
60
+ ? ` target ${'fsd-check'}: added to ${st.targetPath}`
61
+ : st.target === 'present'
62
+ ? ` target ${'fsd-check'}: already present in ${st.targetPath}`
63
+ : ' target fsd-check: NOT added — no parseable project.json / package.json for the app');
64
+ lines.push(st.dependencies === 'added'
65
+ ? ` devDependencies: steiger + @feature-sliced/steiger-plugin added to package.json — run \`${st.installCommand}\``
66
+ : st.dependencies === 'present'
67
+ ? ' devDependencies: already present'
68
+ : ' devDependencies: NOT added — the root package.json could not be parsed');
69
+ lines.push(` run it with: ${st.runCommand} (steiger needs Node >= 22.18)`);
70
+ }
71
+ return lines.join('\n');
72
+ }
@@ -0,0 +1,4 @@
1
+ # CODEOWNERS
2
+ # Define who is required to review changes to matching paths.
3
+ # See https://docs.github.com/articles/about-code-owners
4
+ * @your-team # TODO: set real owners
@@ -0,0 +1,28 @@
1
+ name: Bug report
2
+ description: Report a problem so we can reproduce and fix it.
3
+ labels: ["bug"]
4
+ body:
5
+ - type: textarea
6
+ id: reproduction
7
+ attributes:
8
+ label: Steps to reproduce
9
+ description: List the exact steps that trigger the problem.
10
+ placeholder: |
11
+ 1. ...
12
+ 2. ...
13
+ validations:
14
+ required: true
15
+ - type: textarea
16
+ id: expected
17
+ attributes:
18
+ label: Expected behavior
19
+ description: What did you expect to happen?
20
+ validations:
21
+ required: true
22
+ - type: textarea
23
+ id: actual
24
+ attributes:
25
+ label: Actual behavior
26
+ description: What actually happened instead?
27
+ validations:
28
+ required: true
@@ -0,0 +1,17 @@
1
+ name: Feature request
2
+ description: Propose a new feature or improvement.
3
+ body:
4
+ - type: textarea
5
+ id: problem
6
+ attributes:
7
+ label: What problem does this solve?
8
+ description: Describe the problem or limitation you're running into.
9
+ validations:
10
+ required: true
11
+ - type: textarea
12
+ id: proposal
13
+ attributes:
14
+ label: Proposed solution
15
+ description: Describe the behavior or implementation you'd like to see.
16
+ validations:
17
+ required: true
@@ -0,0 +1,12 @@
1
+ ## Summary
2
+
3
+ <!-- What does this PR do and why? -->
4
+
5
+ ## Changes
6
+
7
+ <!-- List the key changes. -->
8
+
9
+ ## Test plan
10
+
11
+ - [ ] Tests pass locally
12
+ - [ ] Manually verified the change
@@ -0,0 +1,4 @@
1
+ # CODEOWNERS
2
+ # 아래 경로에 매치되는 변경 사항의 필수 리뷰어를 지정합니다.
3
+ # 참고: https://docs.github.com/articles/about-code-owners
4
+ * @your-team # TODO: set real owners
@@ -0,0 +1,28 @@
1
+ name: 버그 리포트
2
+ description: 재현하고 수정할 수 있도록 문제를 신고합니다.
3
+ labels: ["bug"]
4
+ body:
5
+ - type: textarea
6
+ id: reproduction
7
+ attributes:
8
+ label: 재현 방법
9
+ description: 문제를 일으키는 정확한 단계를 나열하세요.
10
+ placeholder: |
11
+ 1. ...
12
+ 2. ...
13
+ validations:
14
+ required: true
15
+ - type: textarea
16
+ id: expected
17
+ attributes:
18
+ label: 예상 동작
19
+ description: 어떤 동작을 예상했나요?
20
+ validations:
21
+ required: true
22
+ - type: textarea
23
+ id: actual
24
+ attributes:
25
+ label: 실제 동작
26
+ description: 실제로는 어떤 일이 일어났나요?
27
+ validations:
28
+ required: true
@@ -0,0 +1,17 @@
1
+ name: 기능 요청
2
+ description: 새로운 기능이나 개선 사항을 제안합니다.
3
+ body:
4
+ - type: textarea
5
+ id: problem
6
+ attributes:
7
+ label: 어떤 문제를 해결하나요?
8
+ description: 지금 겪고 있는 문제나 한계를 설명하세요.
9
+ validations:
10
+ required: true
11
+ - type: textarea
12
+ id: proposal
13
+ attributes:
14
+ label: 제안하는 해결 방법
15
+ description: 원하는 동작이나 구현 방향을 설명하세요.
16
+ validations:
17
+ required: true
@@ -0,0 +1,12 @@
1
+ ## 요약
2
+
3
+ <!-- 이 PR이 무엇을, 왜 하는지 설명하세요. -->
4
+
5
+ ## 변경 사항
6
+
7
+ <!-- 주요 변경 내용을 나열하세요. -->
8
+
9
+ ## 테스트 계획
10
+
11
+ - [ ] 로컬에서 테스트 통과
12
+ - [ ] 변경 사항을 수동으로 확인함
@@ -0,0 +1,125 @@
1
+ // src/generators/add-github-templates/generator.ts
2
+ import { join } from "node:path";
3
+
4
+ // src/generators/shared/dry-run.ts
5
+ function resolveDryRun(options) {
6
+ return process.env["NX_DRY_RUN"] === "true" || (options.dryRun ?? false);
7
+ }
8
+
9
+ // src/generators/shared/toolkit-config-file.ts
10
+ var TOOLKIT_CONFIG_PATH = "toolkit.config.json";
11
+ function readToolkitConfigFile(tree) {
12
+ const raw = tree.read(TOOLKIT_CONFIG_PATH, "utf-8");
13
+ if (raw === null) return { raw: null, parsed: null };
14
+ try {
15
+ const parsed = JSON.parse(raw);
16
+ return {
17
+ raw,
18
+ parsed: typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : null
19
+ };
20
+ } catch {
21
+ return { raw, parsed: null };
22
+ }
23
+ }
24
+ function readToolkitConfig(tree) {
25
+ return readToolkitConfigFile(tree).parsed;
26
+ }
27
+ function resolveLocaleOption(option, config) {
28
+ if (option) return option;
29
+ const locale = config?.["locale"];
30
+ return locale === "ko" || locale === "en" ? locale : "en";
31
+ }
32
+
33
+ // src/generators/shared/template-files.ts
34
+ import { existsSync } from "node:fs";
35
+ import { fileURLToPath } from "node:url";
36
+ import { generateFiles } from "@nx/devkit";
37
+ import { createTree } from "@nx/devkit/testing";
38
+ function generatorFilesDir(generator, fromUrl) {
39
+ for (const relative of [`../${generator}/files`, `./generators/${generator}/files`]) {
40
+ const dir = fileURLToPath(new URL(relative, fromUrl));
41
+ if (existsSync(dir)) return dir;
42
+ }
43
+ throw new Error(`The "${generator}" generator's template files are missing next to ${fileURLToPath(fromUrl)}`);
44
+ }
45
+ function renderTemplateFiles(srcFolder, target, substitutions) {
46
+ const scratch = createTree();
47
+ const seeded = new Set(scratch.listChanges().map((change) => change.path));
48
+ generateFiles(scratch, srcFolder, target, substitutions);
49
+ return scratch.listChanges().flatMap(
50
+ (change) => change.type === "CREATE" && change.content !== null && !seeded.has(change.path) ? [{ filePath: change.path, content: change.content.toString("utf-8") }] : []
51
+ ).sort((a, b) => a.filePath.localeCompare(b.filePath));
52
+ }
53
+
54
+ // src/generators/add-github-templates/render.ts
55
+ var ACTION_LINES = {
56
+ created: "created",
57
+ unchanged: "unchanged (already matches the generated version)",
58
+ skipped: "left as-is (a different file already exists there \u2014 never overwritten)"
59
+ };
60
+ function renderAddGithubTemplatesReport(report) {
61
+ const lines = [];
62
+ if (report.files.length === 0) {
63
+ lines.push("add-github-templates: nothing selected (issue/pr/codeowners all false) \u2014 no files to install.");
64
+ return lines.join("\n");
65
+ }
66
+ if (report.dryRun) {
67
+ lines.push("add-github-templates dry-run \u2014 no files were written.");
68
+ lines.push("");
69
+ for (const file of report.files) {
70
+ lines.push(`${file.filePath}:`);
71
+ lines.push(file.content);
72
+ lines.push("");
73
+ }
74
+ lines.push("Effective decision:");
75
+ }
76
+ for (const file of report.files) {
77
+ lines.push(` ${file.filePath}: ${ACTION_LINES[file.action]}`);
78
+ }
79
+ return lines.join("\n");
80
+ }
81
+
82
+ // src/generators/add-github-templates/generator.ts
83
+ var BUG_REPORT_PATH = ".github/ISSUE_TEMPLATE/bug-report.yml";
84
+ var FEATURE_REQUEST_PATH = ".github/ISSUE_TEMPLATE/feature-request.yml";
85
+ var PULL_REQUEST_TEMPLATE_PATH = ".github/PULL_REQUEST_TEMPLATE.md";
86
+ var CODEOWNERS_PATH = ".github/CODEOWNERS";
87
+ function composeGithubTemplates(groups, locale) {
88
+ const files = generatorFilesDir("add-github-templates", import.meta.url);
89
+ return ["issue", "pr", "codeowners"].filter((group) => groups[group]).flatMap((group) => renderTemplateFiles(join(files, locale, group), ".", {}));
90
+ }
91
+ function runAddGithubTemplates(tree, options) {
92
+ const locale = resolveLocaleOption(options.locale, readToolkitConfig(tree));
93
+ const plan = composeGithubTemplates(
94
+ { issue: options.issue ?? false, pr: options.pr ?? true, codeowners: options.codeowners ?? false },
95
+ locale
96
+ );
97
+ const dryRun = options.dryRun ?? false;
98
+ const files = plan.map(({ filePath, content }) => {
99
+ const existing = tree.read(filePath, "utf-8");
100
+ let action;
101
+ if (existing === null) {
102
+ action = "created";
103
+ if (!dryRun) tree.write(filePath, content);
104
+ } else if (existing === content) {
105
+ action = "unchanged";
106
+ } else {
107
+ action = "skipped";
108
+ }
109
+ return { filePath, action, content };
110
+ });
111
+ return { dryRun, files };
112
+ }
113
+ async function addGithubTemplatesGenerator(tree, options) {
114
+ console.log(renderAddGithubTemplatesReport(runAddGithubTemplates(tree, { ...options, dryRun: resolveDryRun(options) })));
115
+ }
116
+ var generator_default = addGithubTemplatesGenerator;
117
+ export {
118
+ BUG_REPORT_PATH,
119
+ CODEOWNERS_PATH,
120
+ FEATURE_REQUEST_PATH,
121
+ PULL_REQUEST_TEMPLATE_PATH,
122
+ addGithubTemplatesGenerator,
123
+ generator_default as default,
124
+ runAddGithubTemplates
125
+ };
@@ -0,0 +1,26 @@
1
+ const ACTION_LINES = {
2
+ created: 'created',
3
+ unchanged: 'unchanged (already matches the generated version)',
4
+ skipped: 'left as-is (a different file already exists there — never overwritten)',
5
+ };
6
+ export function renderAddGithubTemplatesReport(report) {
7
+ const lines = [];
8
+ if (report.files.length === 0) {
9
+ lines.push('add-github-templates: nothing selected (issue/pr/codeowners all false) — no files to install.');
10
+ return lines.join('\n');
11
+ }
12
+ if (report.dryRun) {
13
+ lines.push('add-github-templates dry-run — no files were written.');
14
+ lines.push('');
15
+ for (const file of report.files) {
16
+ lines.push(`${file.filePath}:`);
17
+ lines.push(file.content);
18
+ lines.push('');
19
+ }
20
+ lines.push('Effective decision:');
21
+ }
22
+ for (const file of report.files) {
23
+ lines.push(` ${file.filePath}: ${ACTION_LINES[file.action]}`);
24
+ }
25
+ return lines.join('\n');
26
+ }