@xanahlight/component-forge 0.1.0 → 1.5.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.
- package/README.md +8 -0
- package/dist/commands/check/index.d.ts +30 -0
- package/dist/commands/check/index.js +255 -0
- package/dist/commands/check/index.js.map +1 -0
- package/dist/commands/explain/index.d.ts +12 -0
- package/dist/commands/explain/index.js +37 -0
- package/dist/commands/explain/index.js.map +1 -0
- package/dist/commands/explain/topics.d.ts +3 -0
- package/dist/commands/explain/topics.js +138 -0
- package/dist/commands/explain/topics.js.map +1 -0
- package/dist/commands/{generate.d.ts → generate/index.d.ts} +1 -1
- package/dist/commands/{generate.js → generate/index.js} +21 -12
- package/dist/commands/generate/index.js.map +1 -0
- package/dist/commands/init/index.d.ts +29 -0
- package/dist/commands/init/index.js +157 -0
- package/dist/commands/init/index.js.map +1 -0
- package/dist/commands/migrate/classifier.d.ts +22 -0
- package/dist/commands/migrate/classifier.js +48 -0
- package/dist/commands/migrate/classifier.js.map +1 -0
- package/dist/commands/migrate/index.d.ts +8 -0
- package/dist/commands/migrate/index.js +33 -0
- package/dist/commands/migrate/index.js.map +1 -0
- package/dist/commands/migrate/plan-builder.d.ts +27 -0
- package/dist/commands/migrate/plan-builder.js +106 -0
- package/dist/commands/migrate/plan-builder.js.map +1 -0
- package/dist/commands/migrate/printer.d.ts +6 -0
- package/dist/commands/migrate/printer.js +46 -0
- package/dist/commands/migrate/printer.js.map +1 -0
- package/dist/commands/validate/index.d.ts +26 -0
- package/dist/commands/{validate.js → validate/index.js} +8 -5
- package/dist/commands/validate/index.js.map +1 -0
- package/dist/index.js +106 -10
- package/dist/index.js.map +1 -1
- package/dist/shared/format.d.ts +26 -0
- package/dist/shared/format.js +40 -0
- package/dist/shared/format.js.map +1 -0
- package/dist/templates/files.d.ts +1 -1
- package/dist/templates/files.js +61 -9
- package/dist/templates/files.js.map +1 -1
- package/dist/types/folder-tree.d.ts +31 -2
- package/dist/types/folder-tree.js +18 -0
- package/dist/types/folder-tree.js.map +1 -1
- package/dist/utils/config.d.ts +19 -6
- package/dist/utils/config.js +76 -14
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/template-resolver.d.ts +1 -1
- package/dist/utils/template-resolver.js +1 -1
- package/dist/utils/template-resolver.js.map +1 -1
- package/package.json +14 -6
- package/dist/commands/generate.js.map +0 -1
- package/dist/commands/init.d.ts +0 -10
- package/dist/commands/init.js +0 -54
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/validate.d.ts +0 -1
- package/dist/commands/validate.js.map +0 -1
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
🌐 English | [Русский](README.ru.md)
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@xanahlight/component-forge)
|
|
6
|
+
[](https://github.com/vladislavprozorov/component-forge/actions/workflows/ci.yml)
|
|
6
7
|
[](https://nodejs.org)
|
|
7
8
|
[](LICENSE)
|
|
8
9
|
|
|
@@ -236,6 +237,13 @@ npm run build
|
|
|
236
237
|
node dist/index.js init fsd
|
|
237
238
|
```
|
|
238
239
|
|
|
240
|
+
Run tests:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
npm test
|
|
244
|
+
npm run test:coverage
|
|
245
|
+
```
|
|
246
|
+
|
|
239
247
|
> Node.js 20+ required.
|
|
240
248
|
|
|
241
249
|
---
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Architecture } from '../../types/folder-tree';
|
|
2
|
+
/**
|
|
3
|
+
* Classifies a FSD violation into one of three kinds:
|
|
4
|
+
* - "same-layer" — both files live in the same FSD layer
|
|
5
|
+
* - "higher-layer" — file imports from a layer that sits ABOVE it
|
|
6
|
+
* - "modular" — modular-arch forbidden dependency
|
|
7
|
+
*/
|
|
8
|
+
export type ViolationKind = 'fsd-same-layer' | 'fsd-higher-layer' | 'modular-forbidden';
|
|
9
|
+
/**
|
|
10
|
+
* Returns a concise, actionable hint for a given violation.
|
|
11
|
+
* Exported for unit testing.
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildHint(kind: ViolationKind, fromLayer: string, toLayer: string): string;
|
|
14
|
+
export interface CheckViolation {
|
|
15
|
+
file: string;
|
|
16
|
+
importPath: string;
|
|
17
|
+
/** Human-readable description of what rule was broken. */
|
|
18
|
+
message: string;
|
|
19
|
+
/** Concrete suggestion on how to fix the violation. */
|
|
20
|
+
hint: string;
|
|
21
|
+
}
|
|
22
|
+
export interface CheckResult {
|
|
23
|
+
violations: CheckViolation[];
|
|
24
|
+
checkedFiles: number;
|
|
25
|
+
}
|
|
26
|
+
export declare function parseImports(source: string): string[];
|
|
27
|
+
export declare function resolveLayer(relPath: string): string | null;
|
|
28
|
+
export declare function collectSourceFiles(dir: string, base?: string): string[];
|
|
29
|
+
export declare function runCheck(srcPath: string, architecture: Architecture): CheckResult;
|
|
30
|
+
export declare function checkCommand(): void;
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.buildHint = buildHint;
|
|
7
|
+
exports.parseImports = parseImports;
|
|
8
|
+
exports.resolveLayer = resolveLayer;
|
|
9
|
+
exports.collectSourceFiles = collectSourceFiles;
|
|
10
|
+
exports.runCheck = runCheck;
|
|
11
|
+
exports.checkCommand = checkCommand;
|
|
12
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
13
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
14
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
15
|
+
const config_1 = require("../../utils/config");
|
|
16
|
+
const logger_1 = require("../../utils/logger");
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// FSD layer hierarchy — higher index = higher layer
|
|
19
|
+
// A layer may only import from layers with a LOWER index.
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
const FSD_LAYER_ORDER = [
|
|
22
|
+
'shared',
|
|
23
|
+
'entities',
|
|
24
|
+
'features',
|
|
25
|
+
'widgets',
|
|
26
|
+
'pages',
|
|
27
|
+
'processes',
|
|
28
|
+
'app',
|
|
29
|
+
];
|
|
30
|
+
// For modular architecture — no strict hierarchy between modules,
|
|
31
|
+
// but modules must not import from app-level dirs and shared cannot
|
|
32
|
+
// import from modules.
|
|
33
|
+
const MODULAR_FORBIDDEN = {
|
|
34
|
+
shared: ['modules', 'core'],
|
|
35
|
+
core: ['modules'],
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Per-pair advice table for FSD violations.
|
|
39
|
+
*
|
|
40
|
+
* Key format: "<fromLayer>-><toLayer>"
|
|
41
|
+
* Falls back to generic advice when a specific pair is not listed.
|
|
42
|
+
*/
|
|
43
|
+
const FSD_PAIR_HINTS = {
|
|
44
|
+
// Same-layer cross-imports
|
|
45
|
+
'features->features': 'Extract the shared logic into shared/ (e.g. shared/lib or shared/api) ' +
|
|
46
|
+
'or lift it into a widget that composes both features.',
|
|
47
|
+
'entities->entities': 'Move the shared data type or helper to shared/. ' +
|
|
48
|
+
'Entities must remain independent of each other.',
|
|
49
|
+
'widgets->widgets': 'Extract the common UI piece into shared/ui or compose them inside a page instead.',
|
|
50
|
+
'pages->pages': 'Pages should not depend on each other. ' +
|
|
51
|
+
'Move the shared UI to widgets/ or shared/ui.',
|
|
52
|
+
// Higher-layer imports (lower importing from higher)
|
|
53
|
+
'shared->entities': 'shared/ is the foundation — it must not know about entities. ' +
|
|
54
|
+
'Move the type/helper to shared/ itself, or invert the dependency.',
|
|
55
|
+
'shared->features': 'shared/ must not import from features/. ' +
|
|
56
|
+
'Extract only the primitive/generic part into shared/.',
|
|
57
|
+
'shared->widgets': 'shared/ must not import from widgets/. ' +
|
|
58
|
+
'The component should live in shared/ui or be passed as a prop.',
|
|
59
|
+
'shared->pages': 'shared/ must not import from pages/. ' +
|
|
60
|
+
'Anything shared across pages belongs in shared/ or widgets/.',
|
|
61
|
+
'entities->features': 'Entities must not depend on features. ' +
|
|
62
|
+
'If you need a callback/handler, pass it as a prop or use an event bus.',
|
|
63
|
+
'entities->widgets': 'Entities must not depend on widgets. ' +
|
|
64
|
+
'Lift the dependency inversion: pass the widget as a ReactNode prop.',
|
|
65
|
+
'entities->pages': 'Entities must not depend on pages. ' +
|
|
66
|
+
'Pages are composed at the top — entities should never reference them.',
|
|
67
|
+
'features->widgets': 'Features must not import from widgets. ' +
|
|
68
|
+
'A widget composes features, not the other way around.',
|
|
69
|
+
'features->pages': 'Features must not import from pages. ' +
|
|
70
|
+
'Consider moving the shared piece down to shared/ or entities/.',
|
|
71
|
+
'widgets->pages': 'Widgets must not import from pages. ' +
|
|
72
|
+
'Pages are the top-level composers — extract the shared part into widgets/ itself.',
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Returns a concise, actionable hint for a given violation.
|
|
76
|
+
* Exported for unit testing.
|
|
77
|
+
*/
|
|
78
|
+
function buildHint(kind, fromLayer, toLayer) {
|
|
79
|
+
if (kind === 'modular-forbidden') {
|
|
80
|
+
if (fromLayer === 'shared') {
|
|
81
|
+
return ('shared/ is infrastructure — it must not import from modules/. ' +
|
|
82
|
+
'Move the dependency into the module itself or create a shared abstraction.');
|
|
83
|
+
}
|
|
84
|
+
if (fromLayer === 'core') {
|
|
85
|
+
return ('core/ sets up the application shell and must not depend on feature modules. ' +
|
|
86
|
+
'Use dependency injection or an event bus to decouple them.');
|
|
87
|
+
}
|
|
88
|
+
return (`"${fromLayer}" must not import from "${toLayer}" in modular architecture. ` +
|
|
89
|
+
'Consider inverting the dependency or extracting shared logic into shared/.');
|
|
90
|
+
}
|
|
91
|
+
const key = `${fromLayer}->${toLayer}`;
|
|
92
|
+
if (FSD_PAIR_HINTS[key])
|
|
93
|
+
return FSD_PAIR_HINTS[key];
|
|
94
|
+
// Generic fallback
|
|
95
|
+
if (kind === 'fsd-same-layer') {
|
|
96
|
+
return (`Two slices inside "${fromLayer}" must not import from each other. ` +
|
|
97
|
+
'Extract shared logic to shared/ or compose them in a higher layer.');
|
|
98
|
+
}
|
|
99
|
+
// fsd-higher-layer fallback
|
|
100
|
+
return (`"${fromLayer}" sits below "${toLayer}" in the FSD hierarchy and must not import from it. ` +
|
|
101
|
+
'Move the shared code down to a layer that both can depend on (e.g. shared/ or entities/).');
|
|
102
|
+
}
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// Import parsing — extracts all static import paths from a TS/TSX file
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
const IMPORT_RE = /^\s*(?:import|export)\s+(?:[^'"]*\s+from\s+)?['"]([^'"]+)['"]/gm;
|
|
107
|
+
function parseImports(source) {
|
|
108
|
+
const imports = [];
|
|
109
|
+
let match;
|
|
110
|
+
const re = new RegExp(IMPORT_RE.source, IMPORT_RE.flags);
|
|
111
|
+
while ((match = re.exec(source)) !== null) {
|
|
112
|
+
imports.push(match[1]);
|
|
113
|
+
}
|
|
114
|
+
return imports;
|
|
115
|
+
}
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
// Layer resolution — given a file path relative to srcDir, returns its layer
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
function resolveLayer(relPath) {
|
|
120
|
+
// relPath looks like "features/auth/index.ts" or "shared/ui/Button.ts"
|
|
121
|
+
const parts = relPath.split(node_path_1.default.sep);
|
|
122
|
+
return parts[0] ?? null;
|
|
123
|
+
}
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// FSD violation check
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
function checkFsdViolations(srcPath, relFilePath, imports) {
|
|
128
|
+
const violations = [];
|
|
129
|
+
const fileLayer = resolveLayer(relFilePath);
|
|
130
|
+
if (!fileLayer)
|
|
131
|
+
return violations;
|
|
132
|
+
const fileLayerIdx = FSD_LAYER_ORDER.indexOf(fileLayer);
|
|
133
|
+
if (fileLayerIdx === -1)
|
|
134
|
+
return violations; // unknown layer — skip
|
|
135
|
+
for (const imp of imports) {
|
|
136
|
+
// Only check relative imports that could cross layer boundaries
|
|
137
|
+
// e.g. "../../features/auth" — resolve to get the target layer
|
|
138
|
+
if (!imp.startsWith('.'))
|
|
139
|
+
continue;
|
|
140
|
+
const fileDir = node_path_1.default.dirname(node_path_1.default.join(srcPath, relFilePath));
|
|
141
|
+
const resolved = node_path_1.default.resolve(fileDir, imp);
|
|
142
|
+
const relResolved = node_path_1.default.relative(srcPath, resolved);
|
|
143
|
+
const targetLayer = resolveLayer(relResolved);
|
|
144
|
+
if (!targetLayer)
|
|
145
|
+
continue;
|
|
146
|
+
const targetLayerIdx = FSD_LAYER_ORDER.indexOf(targetLayer);
|
|
147
|
+
if (targetLayerIdx === -1)
|
|
148
|
+
continue; // unknown target layer
|
|
149
|
+
// Violation: importing from the same layer OR a higher layer
|
|
150
|
+
if (targetLayerIdx >= fileLayerIdx) {
|
|
151
|
+
const kind = targetLayerIdx === fileLayerIdx ? 'fsd-same-layer' : 'fsd-higher-layer';
|
|
152
|
+
violations.push({
|
|
153
|
+
file: relFilePath,
|
|
154
|
+
importPath: imp,
|
|
155
|
+
message: `Layer "${fileLayer}" must not import from "${targetLayer}" ` +
|
|
156
|
+
`(${targetLayer} is at the same level or higher in FSD hierarchy)`,
|
|
157
|
+
hint: buildHint(kind, fileLayer, targetLayer),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return violations;
|
|
162
|
+
}
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
// Modular violation check
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
function checkModularViolations(srcPath, relFilePath, imports) {
|
|
167
|
+
const violations = [];
|
|
168
|
+
const fileLayer = resolveLayer(relFilePath);
|
|
169
|
+
if (!fileLayer)
|
|
170
|
+
return violations;
|
|
171
|
+
const forbidden = MODULAR_FORBIDDEN[fileLayer];
|
|
172
|
+
if (!forbidden)
|
|
173
|
+
return violations;
|
|
174
|
+
for (const imp of imports) {
|
|
175
|
+
if (!imp.startsWith('.'))
|
|
176
|
+
continue;
|
|
177
|
+
const fileDir = node_path_1.default.dirname(node_path_1.default.join(srcPath, relFilePath));
|
|
178
|
+
const resolved = node_path_1.default.resolve(fileDir, imp);
|
|
179
|
+
const relResolved = node_path_1.default.relative(srcPath, resolved);
|
|
180
|
+
const targetLayer = resolveLayer(relResolved);
|
|
181
|
+
if (!targetLayer)
|
|
182
|
+
continue;
|
|
183
|
+
if (forbidden.includes(targetLayer)) {
|
|
184
|
+
violations.push({
|
|
185
|
+
file: relFilePath,
|
|
186
|
+
importPath: imp,
|
|
187
|
+
message: `Layer "${fileLayer}" must not import from "${targetLayer}" in modular architecture`,
|
|
188
|
+
hint: buildHint('modular-forbidden', fileLayer, targetLayer),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return violations;
|
|
193
|
+
}
|
|
194
|
+
// ---------------------------------------------------------------------------
|
|
195
|
+
// File collector — recursively finds .ts / .tsx files under srcPath
|
|
196
|
+
// ---------------------------------------------------------------------------
|
|
197
|
+
function collectSourceFiles(dir, base = dir) {
|
|
198
|
+
const results = [];
|
|
199
|
+
if (!node_fs_1.default.existsSync(dir))
|
|
200
|
+
return results;
|
|
201
|
+
for (const entry of node_fs_1.default.readdirSync(dir, { withFileTypes: true })) {
|
|
202
|
+
const full = node_path_1.default.join(dir, entry.name);
|
|
203
|
+
if (entry.isDirectory()) {
|
|
204
|
+
results.push(...collectSourceFiles(full, base));
|
|
205
|
+
}
|
|
206
|
+
else if (/\.(ts|tsx)$/.test(entry.name) && !entry.name.endsWith('.test.ts')) {
|
|
207
|
+
results.push(node_path_1.default.relative(base, full));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return results;
|
|
211
|
+
}
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
// Core check logic — exported for testing
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
function runCheck(srcPath, architecture) {
|
|
216
|
+
const files = collectSourceFiles(srcPath);
|
|
217
|
+
const violations = [];
|
|
218
|
+
for (const relFile of files) {
|
|
219
|
+
const fullPath = node_path_1.default.join(srcPath, relFile);
|
|
220
|
+
const source = node_fs_1.default.readFileSync(fullPath, 'utf8');
|
|
221
|
+
const imports = parseImports(source);
|
|
222
|
+
if (architecture === 'fsd') {
|
|
223
|
+
violations.push(...checkFsdViolations(srcPath, relFile, imports));
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
violations.push(...checkModularViolations(srcPath, relFile, imports));
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return { violations, checkedFiles: files.length };
|
|
230
|
+
}
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
// Command entry point
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
function checkCommand() {
|
|
235
|
+
const config = (0, config_1.loadProjectConfig)();
|
|
236
|
+
const srcPath = node_path_1.default.join(process.cwd(), config.srcDir);
|
|
237
|
+
logger_1.logger.info(`Checking architecture boundaries (${config.architecture})…\n`);
|
|
238
|
+
const { violations, checkedFiles } = runCheck(srcPath, config.architecture);
|
|
239
|
+
if (violations.length === 0) {
|
|
240
|
+
logger_1.logger.success(`✓ No violations found in ${checkedFiles} file(s). Architecture looks clean!`);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
console.log(chalk_1.default.red(`✖ Found ${violations.length} violation(s) in ${checkedFiles} file(s):\n`));
|
|
244
|
+
for (const v of violations) {
|
|
245
|
+
console.log(chalk_1.default.bold(chalk_1.default.white(` ${v.file}`)));
|
|
246
|
+
console.log(chalk_1.default.gray(` import "${v.importPath}"`));
|
|
247
|
+
console.log(chalk_1.default.red(` ✗ ${v.message}`));
|
|
248
|
+
console.log(chalk_1.default.yellow(` → Fix: ${v.hint}\n`));
|
|
249
|
+
}
|
|
250
|
+
if (config.architecture === 'fsd') {
|
|
251
|
+
console.log(chalk_1.default.gray(' FSD order (low → high): shared → entities → features → widgets → pages → app\n'));
|
|
252
|
+
}
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/check/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TOPICS } from './topics';
|
|
2
|
+
export { TOPICS };
|
|
3
|
+
export declare const AVAILABLE_TOPICS: readonly string[];
|
|
4
|
+
/**
|
|
5
|
+
* Renders the requested topic to a string.
|
|
6
|
+
* Pure function — no stdout side-effects — making it fully testable.
|
|
7
|
+
*/
|
|
8
|
+
export declare function renderTopic(topic: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* CLI entry point — writes the rendered topic to stdout.
|
|
11
|
+
*/
|
|
12
|
+
export declare function explainCommand(topic: string): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.AVAILABLE_TOPICS = exports.TOPICS = void 0;
|
|
7
|
+
exports.renderTopic = renderTopic;
|
|
8
|
+
exports.explainCommand = explainCommand;
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const format_1 = require("../../shared/format");
|
|
11
|
+
const topics_1 = require("./topics");
|
|
12
|
+
Object.defineProperty(exports, "TOPICS", { enumerable: true, get: function () { return topics_1.TOPICS; } });
|
|
13
|
+
exports.AVAILABLE_TOPICS = Object.keys(topics_1.TOPICS);
|
|
14
|
+
/**
|
|
15
|
+
* Renders the requested topic to a string.
|
|
16
|
+
* Pure function — no stdout side-effects — making it fully testable.
|
|
17
|
+
*/
|
|
18
|
+
function renderTopic(topic) {
|
|
19
|
+
const renderer = topics_1.TOPICS[topic.toLowerCase()];
|
|
20
|
+
if (!renderer) {
|
|
21
|
+
return [
|
|
22
|
+
chalk_1.default.red(`\n Unknown topic: "${topic}"\n`),
|
|
23
|
+
format_1.fmt.line(` Available topics: ${chalk_1.default.cyan(exports.AVAILABLE_TOPICS.join(', '))}`),
|
|
24
|
+
format_1.fmt.line(''),
|
|
25
|
+
format_1.fmt.line(` Example: component-forge explain fsd`),
|
|
26
|
+
format_1.fmt.line(''),
|
|
27
|
+
].join('\n');
|
|
28
|
+
}
|
|
29
|
+
return renderer();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* CLI entry point — writes the rendered topic to stdout.
|
|
33
|
+
*/
|
|
34
|
+
function explainCommand(topic) {
|
|
35
|
+
process.stdout.write(renderTopic(topic));
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/explain/index.ts"],"names":[],"mappings":";;;;;;AAaA,kCAcC;AAKD,wCAEC;AAlCD,kDAAyB;AAEzB,gDAAyC;AAEzC,qCAAiC;AAExB,uFAFA,eAAM,OAEA;AACF,QAAA,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,eAAM,CAAsB,CAAA;AAExE;;;GAGG;AACH,SAAgB,WAAW,CAAC,KAAa;IACvC,MAAM,QAAQ,GAAG,eAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAA;IAE5C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,eAAK,CAAC,GAAG,CAAC,uBAAuB,KAAK,KAAK,CAAC;YAC5C,YAAG,CAAC,IAAI,CAAC,uBAAuB,eAAK,CAAC,IAAI,CAAC,wBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;YAC1E,YAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACZ,YAAG,CAAC,IAAI,CAAC,wCAAwC,CAAC;YAClD,YAAG,CAAC,IAAI,CAAC,EAAE,CAAC;SACb,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACd,CAAC;IAED,OAAO,QAAQ,EAAE,CAAA;AACnB,CAAC;AAED;;GAEG;AACH,SAAgB,cAAc,CAAC,KAAa;IAC1C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAA;AAC1C,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TOPICS = void 0;
|
|
4
|
+
const format_1 = require("../../shared/format");
|
|
5
|
+
exports.TOPICS = {
|
|
6
|
+
fsd: renderFsd,
|
|
7
|
+
modular: renderModular,
|
|
8
|
+
layers: renderLayers,
|
|
9
|
+
all: renderAll,
|
|
10
|
+
};
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// FSD
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
function renderFsd() {
|
|
15
|
+
return [
|
|
16
|
+
format_1.fmt.h1('Feature-Sliced Design (FSD)'),
|
|
17
|
+
format_1.fmt.rule(),
|
|
18
|
+
format_1.fmt.line(''),
|
|
19
|
+
format_1.fmt.line('FSD is an architectural methodology for frontend applications that organises'),
|
|
20
|
+
format_1.fmt.line('code by ' + format_1.fmt.dim('business features') + ' instead of technical roles.'),
|
|
21
|
+
format_1.fmt.line(''),
|
|
22
|
+
format_1.fmt.h2('Layer hierarchy (low → high)'),
|
|
23
|
+
format_1.fmt.line(''),
|
|
24
|
+
format_1.fmt.line(` ${format_1.fmt.tag('shared')} ${format_1.fmt.dim('Reusable UI, utilities, constants — no business logic')}`),
|
|
25
|
+
format_1.fmt.line(` ${format_1.fmt.tag('entities')} ${format_1.fmt.dim('Business entities: User, Order, Product')}`),
|
|
26
|
+
format_1.fmt.line(` ${format_1.fmt.tag('features')} ${format_1.fmt.dim('User actions: auth, search, payment')}`),
|
|
27
|
+
format_1.fmt.line(` ${format_1.fmt.tag('widgets')} ${format_1.fmt.dim('Composite blocks assembled from entities + features')}`),
|
|
28
|
+
format_1.fmt.line(` ${format_1.fmt.tag('pages')} ${format_1.fmt.dim('Full application screens')}`),
|
|
29
|
+
format_1.fmt.line(` ${format_1.fmt.tag('app')} ${format_1.fmt.dim('App-wide: router, providers, global styles')}`),
|
|
30
|
+
format_1.fmt.line(''),
|
|
31
|
+
format_1.fmt.h2('Import rules'),
|
|
32
|
+
format_1.fmt.line(''),
|
|
33
|
+
format_1.fmt.arrow('features', 'entities', true),
|
|
34
|
+
format_1.fmt.arrow('features', 'shared', true),
|
|
35
|
+
format_1.fmt.arrow('features', 'features', false),
|
|
36
|
+
format_1.fmt.arrow('entities', 'features', false),
|
|
37
|
+
format_1.fmt.arrow('shared', 'entities', false),
|
|
38
|
+
format_1.fmt.line(''),
|
|
39
|
+
format_1.fmt.line(format_1.fmt.dim(' A layer may only import from layers below it.')),
|
|
40
|
+
format_1.fmt.line(''),
|
|
41
|
+
format_1.fmt.h2('Public API rule'),
|
|
42
|
+
format_1.fmt.line(''),
|
|
43
|
+
format_1.fmt.line(' Each slice must expose its interface through a single index.ts:'),
|
|
44
|
+
format_1.fmt.line(''),
|
|
45
|
+
format_1.fmt.line(format_1.fmt.dim(' features/auth/index.ts ← public API')),
|
|
46
|
+
format_1.fmt.line(format_1.fmt.dim(' features/auth/model.ts ← private implementation')),
|
|
47
|
+
format_1.fmt.line(''),
|
|
48
|
+
format_1.fmt.ok('import { useAuth } from "@/features/auth"'),
|
|
49
|
+
format_1.fmt.no('import { authStore } from "@/features/auth/model"'),
|
|
50
|
+
format_1.fmt.line(''),
|
|
51
|
+
format_1.fmt.rule(),
|
|
52
|
+
format_1.fmt.line(''),
|
|
53
|
+
format_1.fmt.line(' component-forge init fsd — scaffold FSD structure'),
|
|
54
|
+
format_1.fmt.line(' component-forge check — validate FSD boundaries'),
|
|
55
|
+
format_1.fmt.line(''),
|
|
56
|
+
].join('\n');
|
|
57
|
+
}
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Modular
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
function renderModular() {
|
|
62
|
+
return [
|
|
63
|
+
format_1.fmt.h1('Modular Architecture'),
|
|
64
|
+
format_1.fmt.rule(),
|
|
65
|
+
format_1.fmt.line(''),
|
|
66
|
+
format_1.fmt.line('Modular architecture organises code into self-contained modules'),
|
|
67
|
+
format_1.fmt.line('that encapsulate a business domain end-to-end.'),
|
|
68
|
+
format_1.fmt.line(''),
|
|
69
|
+
format_1.fmt.h2('Structure'),
|
|
70
|
+
format_1.fmt.line(''),
|
|
71
|
+
format_1.fmt.line(` ${format_1.fmt.tag('core')} ${format_1.fmt.dim('App-wide infra: routing, DI, config')}`),
|
|
72
|
+
format_1.fmt.line(` ${format_1.fmt.tag('modules')} ${format_1.fmt.dim('Business domains: AuthModule, CartModule')}`),
|
|
73
|
+
format_1.fmt.line(` ${format_1.fmt.tag('shared')} ${format_1.fmt.dim('Design system, utilities, types')}`),
|
|
74
|
+
format_1.fmt.line(''),
|
|
75
|
+
format_1.fmt.h2('Import rules'),
|
|
76
|
+
format_1.fmt.line(''),
|
|
77
|
+
format_1.fmt.arrow('modules', 'modules', true),
|
|
78
|
+
format_1.fmt.arrow('modules', 'shared', true),
|
|
79
|
+
format_1.fmt.arrow('shared', 'modules', false),
|
|
80
|
+
format_1.fmt.arrow('core', 'modules', false),
|
|
81
|
+
format_1.fmt.line(''),
|
|
82
|
+
format_1.fmt.line(format_1.fmt.dim(' shared and core must not depend on modules — they are foundational.')),
|
|
83
|
+
format_1.fmt.line(''),
|
|
84
|
+
format_1.fmt.h2('When to choose Modular vs FSD'),
|
|
85
|
+
format_1.fmt.line(''),
|
|
86
|
+
format_1.fmt.line(' FSD — large teams, complex domain, strict layer isolation'),
|
|
87
|
+
format_1.fmt.line(' Modular — medium apps, clear domain boundaries, less ceremony'),
|
|
88
|
+
format_1.fmt.line(''),
|
|
89
|
+
format_1.fmt.rule(),
|
|
90
|
+
format_1.fmt.line(''),
|
|
91
|
+
format_1.fmt.line(' component-forge init modular — scaffold modular structure'),
|
|
92
|
+
format_1.fmt.line(' component-forge check — validate modular boundaries'),
|
|
93
|
+
format_1.fmt.line(''),
|
|
94
|
+
].join('\n');
|
|
95
|
+
}
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Layers
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
const FSD_LAYERS = [
|
|
100
|
+
['shared', 'Reusable: UI kit, utils, constants, types, API clients'],
|
|
101
|
+
['entities', 'Business objects with their data model and UI: User, Product'],
|
|
102
|
+
['features', 'User-facing use cases: LoginForm, AddToCart, SearchBar'],
|
|
103
|
+
['widgets', 'Complex composites: Header, Sidebar, ProductCard'],
|
|
104
|
+
['pages', 'Application routes/screens assembled from widgets'],
|
|
105
|
+
['app', 'Bootstrap: router, global providers, themes'],
|
|
106
|
+
];
|
|
107
|
+
function getAllowedBelow(layer) {
|
|
108
|
+
const order = ['shared', 'entities', 'features', 'widgets', 'pages', 'app'];
|
|
109
|
+
const idx = order.indexOf(layer);
|
|
110
|
+
if (idx <= 0)
|
|
111
|
+
return idx === 0 ? 'none (bottom layer)' : 'unknown';
|
|
112
|
+
return order.slice(0, idx).join(', ');
|
|
113
|
+
}
|
|
114
|
+
function renderLayers() {
|
|
115
|
+
return [
|
|
116
|
+
format_1.fmt.h1('FSD Layer Reference'),
|
|
117
|
+
format_1.fmt.rule(),
|
|
118
|
+
format_1.fmt.line(''),
|
|
119
|
+
...FSD_LAYERS.flatMap(([name, desc]) => [
|
|
120
|
+
` ${format_1.fmt.dim(name)}`,
|
|
121
|
+
format_1.fmt.line(format_1.fmt.dim(` ${desc}`)),
|
|
122
|
+
format_1.fmt.line(format_1.fmt.dim(` Allowed imports: ${getAllowedBelow(name)}`)),
|
|
123
|
+
'',
|
|
124
|
+
]),
|
|
125
|
+
format_1.fmt.rule(),
|
|
126
|
+
format_1.fmt.line(''),
|
|
127
|
+
format_1.fmt.line(' component-forge explain fsd — full FSD overview'),
|
|
128
|
+
format_1.fmt.line(' component-forge check — detect boundary violations'),
|
|
129
|
+
format_1.fmt.line(''),
|
|
130
|
+
].join('\n');
|
|
131
|
+
}
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// All
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
function renderAll() {
|
|
136
|
+
return [renderFsd(), renderModular(), renderLayers()].join('\n');
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=topics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"topics.js","sourceRoot":"","sources":["../../../src/commands/explain/topics.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,11 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.generateCommand = generateCommand;
|
|
7
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
7
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const config_1 = require("../../utils/config");
|
|
10
|
+
const logger_1 = require("../../utils/logger");
|
|
11
|
+
const template_resolver_1 = require("../../utils/template-resolver");
|
|
12
12
|
const placementByArchitecture = {
|
|
13
13
|
fsd: {
|
|
14
14
|
feature: 'features',
|
|
@@ -23,6 +23,17 @@ const placementByArchitecture = {
|
|
|
23
23
|
},
|
|
24
24
|
};
|
|
25
25
|
// ---------------------------------------------------------------------------
|
|
26
|
+
// Slice descriptions — shown in dry-run and success messages
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
const sliceDescriptions = {
|
|
29
|
+
feature: 'full vertical slice — ui + model + api',
|
|
30
|
+
entity: 'data-layer slice — model + api (no UI)',
|
|
31
|
+
widget: 'composite UI block — ui + model (no api)',
|
|
32
|
+
page: 'route-level shell — ui only',
|
|
33
|
+
component: 'pure UI atom — flat component (no model/api)',
|
|
34
|
+
module: 'vertical module — ui + model + api',
|
|
35
|
+
};
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
26
37
|
// Path resolution
|
|
27
38
|
// ---------------------------------------------------------------------------
|
|
28
39
|
/**
|
|
@@ -66,7 +77,8 @@ function generateCommand(sliceType, sliceName, options = {}) {
|
|
|
66
77
|
const sliceBaseName = node_path_1.default.basename(sliceName);
|
|
67
78
|
const files = (0, template_resolver_1.resolveSliceFiles)(sliceType, sliceBaseName, templatesDir);
|
|
68
79
|
if (dryRun) {
|
|
69
|
-
logger_1.logger.info(`Dry run — no files will be written
|
|
80
|
+
logger_1.logger.info(`Dry run — no files will be written.`);
|
|
81
|
+
logger_1.logger.info(`Type: ${sliceType} (${sliceDescriptions[sliceType]})\n`);
|
|
70
82
|
printDryRun(slicePath + '/');
|
|
71
83
|
for (const relativePath of Object.keys(files)) {
|
|
72
84
|
printDryRun(node_path_1.default.join(slicePath, relativePath));
|
|
@@ -81,11 +93,8 @@ function generateCommand(sliceType, sliceName, options = {}) {
|
|
|
81
93
|
for (const [relativePath, content] of Object.entries(files)) {
|
|
82
94
|
writeFile(node_path_1.default.join(slicePath, relativePath), content);
|
|
83
95
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
logger_1.logger.info(`Generated ${sliceType} "${sliceName}" successfully.`);
|
|
89
|
-
}
|
|
96
|
+
const source = templatesDir ? ' (custom templates)' : '';
|
|
97
|
+
logger_1.logger.info(`\nGenerated ${sliceType} "${sliceName}"${source}`);
|
|
98
|
+
logger_1.logger.info(`Structure: ${sliceDescriptions[sliceType]}`);
|
|
90
99
|
}
|
|
91
|
-
//# sourceMappingURL=
|
|
100
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/generate/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Architecture, FolderTree } from '../../types/folder-tree';
|
|
2
|
+
import { CONFIG_FILENAMES, loadProjectConfig } from '../../utils/config';
|
|
3
|
+
export { CONFIG_FILENAMES };
|
|
4
|
+
export { loadProjectConfig };
|
|
5
|
+
/**
|
|
6
|
+
* Recursively creates folder structure from a FolderTree definition.
|
|
7
|
+
* Returns the list of created paths (relative to cwd) for summary output.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createStructure(tree: FolderTree, basePath: string, cwd: string): string[];
|
|
10
|
+
export interface InitAnswers {
|
|
11
|
+
architecture: Architecture;
|
|
12
|
+
srcDir: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Runs interactive prompts to collect init parameters.
|
|
16
|
+
* Throws if the user cancels (Ctrl+C) — caller handles the exit.
|
|
17
|
+
*/
|
|
18
|
+
export declare function promptInitAnswers(): Promise<InitAnswers>;
|
|
19
|
+
/**
|
|
20
|
+
* Performs the actual init: creates folder structure + writes config.
|
|
21
|
+
* Exported so it can be called directly (non-interactive) or from tests.
|
|
22
|
+
*/
|
|
23
|
+
export declare function runInit(architecture: Architecture, srcDir: string, projectRoot: string): void;
|
|
24
|
+
/**
|
|
25
|
+
* Called from index.ts.
|
|
26
|
+
* If architecture is provided — runs non-interactively (backwards-compatible).
|
|
27
|
+
* If omitted — runs interactive prompts.
|
|
28
|
+
*/
|
|
29
|
+
export declare function initCommand(architecture?: Architecture): void;
|