@xanahlight/component-forge 0.1.0 → 1.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 (70) hide show
  1. package/README.md +8 -0
  2. package/dist/commands/check/check.test.d.ts +1 -0
  3. package/dist/commands/check/check.test.js +151 -0
  4. package/dist/commands/check/check.test.js.map +1 -0
  5. package/dist/commands/check/index.d.ts +15 -0
  6. package/dist/commands/check/index.js +186 -0
  7. package/dist/commands/check/index.js.map +1 -0
  8. package/dist/commands/explain/explain.test.d.ts +1 -0
  9. package/dist/commands/explain/explain.test.js +57 -0
  10. package/dist/commands/explain/explain.test.js.map +1 -0
  11. package/dist/commands/explain/index.d.ts +12 -0
  12. package/dist/commands/explain/index.js +37 -0
  13. package/dist/commands/explain/index.js.map +1 -0
  14. package/dist/commands/explain/topics.d.ts +3 -0
  15. package/dist/commands/explain/topics.js +138 -0
  16. package/dist/commands/explain/topics.js.map +1 -0
  17. package/dist/commands/generate/index.d.ts +6 -0
  18. package/dist/commands/generate/index.js +100 -0
  19. package/dist/commands/generate/index.js.map +1 -0
  20. package/dist/commands/init/index.d.ts +29 -0
  21. package/dist/commands/init/index.js +157 -0
  22. package/dist/commands/init/index.js.map +1 -0
  23. package/dist/commands/migrate/classifier.d.ts +22 -0
  24. package/dist/commands/migrate/classifier.js +48 -0
  25. package/dist/commands/migrate/classifier.js.map +1 -0
  26. package/dist/commands/migrate/index.d.ts +8 -0
  27. package/dist/commands/migrate/index.js +33 -0
  28. package/dist/commands/migrate/index.js.map +1 -0
  29. package/dist/commands/migrate/migrate.test.d.ts +1 -0
  30. package/dist/commands/migrate/migrate.test.js +176 -0
  31. package/dist/commands/migrate/migrate.test.js.map +1 -0
  32. package/dist/commands/migrate/plan-builder.d.ts +27 -0
  33. package/dist/commands/migrate/plan-builder.js +106 -0
  34. package/dist/commands/migrate/plan-builder.js.map +1 -0
  35. package/dist/commands/migrate/printer.d.ts +6 -0
  36. package/dist/commands/migrate/printer.js +46 -0
  37. package/dist/commands/migrate/printer.js.map +1 -0
  38. package/dist/commands/validate/index.d.ts +26 -0
  39. package/dist/commands/validate/index.js +122 -0
  40. package/dist/commands/validate/index.js.map +1 -0
  41. package/dist/commands/validate/validate.test.d.ts +1 -0
  42. package/dist/commands/validate/validate.test.js +163 -0
  43. package/dist/commands/validate/validate.test.js.map +1 -0
  44. package/dist/index.js +54 -10
  45. package/dist/index.js.map +1 -1
  46. package/dist/shared/format.d.ts +26 -0
  47. package/dist/shared/format.js +40 -0
  48. package/dist/shared/format.js.map +1 -0
  49. package/dist/templates/files.d.ts +1 -1
  50. package/dist/templates/files.js +61 -9
  51. package/dist/templates/files.js.map +1 -1
  52. package/dist/templates/files.test.d.ts +1 -0
  53. package/dist/templates/files.test.js +174 -0
  54. package/dist/templates/files.test.js.map +1 -0
  55. package/dist/types/folder-tree.d.ts +31 -2
  56. package/dist/types/folder-tree.js +18 -0
  57. package/dist/types/folder-tree.js.map +1 -1
  58. package/dist/utils/config.d.ts +19 -6
  59. package/dist/utils/config.js +76 -14
  60. package/dist/utils/config.js.map +1 -1
  61. package/dist/utils/config.test.d.ts +1 -0
  62. package/dist/utils/config.test.js +117 -0
  63. package/dist/utils/config.test.js.map +1 -0
  64. package/dist/utils/template-resolver.d.ts +1 -1
  65. package/dist/utils/template-resolver.js +1 -1
  66. package/dist/utils/template-resolver.js.map +1 -1
  67. package/dist/utils/template-resolver.test.d.ts +1 -0
  68. package/dist/utils/template-resolver.test.js +86 -0
  69. package/dist/utils/template-resolver.test.js.map +1 -0
  70. package/package.json +13 -5
@@ -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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"}
@@ -0,0 +1,6 @@
1
+ import { SliceType } from '../../types/folder-tree';
2
+ export { SliceType };
3
+ export interface GenerateOptions {
4
+ dryRun?: boolean;
5
+ }
6
+ export declare function generateCommand(sliceType: SliceType, sliceName: string, options?: GenerateOptions): void;
@@ -0,0 +1,100 @@
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.generateCommand = generateCommand;
7
+ const node_path_1 = __importDefault(require("node:path"));
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
+ const placementByArchitecture = {
13
+ fsd: {
14
+ feature: 'features',
15
+ entity: 'entities',
16
+ widget: 'widgets',
17
+ page: 'pages',
18
+ component: 'shared/ui',
19
+ },
20
+ modular: {
21
+ module: 'modules',
22
+ component: 'shared/ui',
23
+ },
24
+ };
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
+ // ---------------------------------------------------------------------------
37
+ // Path resolution
38
+ // ---------------------------------------------------------------------------
39
+ /**
40
+ * Resolves the absolute path for the slice being generated.
41
+ * Supports nested names like "forms/Input" → src/shared/ui/forms/Input
42
+ */
43
+ function resolveSlicePath(config, sliceType, sliceName) {
44
+ const placement = placementByArchitecture[config.architecture][sliceType];
45
+ if (!placement) {
46
+ const available = Object.keys(placementByArchitecture[config.architecture]).join(', ');
47
+ logger_1.logger.error(`Slice type "${sliceType}" is not supported for ${config.architecture} architecture.`);
48
+ logger_1.logger.info(`Available types for ${config.architecture}: ${available}`);
49
+ process.exit(1);
50
+ }
51
+ return node_path_1.default.join(process.cwd(), config.srcDir, placement, sliceName);
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // File I/O
55
+ // ---------------------------------------------------------------------------
56
+ function writeFile(filePath, content) {
57
+ fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(filePath));
58
+ fs_extra_1.default.writeFileSync(filePath, content);
59
+ logger_1.logger.success(`Created: ${node_path_1.default.relative(process.cwd(), filePath)}`);
60
+ }
61
+ function printDryRun(filePath) {
62
+ logger_1.logger.info(`Would create: ${node_path_1.default.relative(process.cwd(), filePath)}`);
63
+ }
64
+ function generateCommand(sliceType, sliceName, options = {}) {
65
+ const { dryRun = false } = options;
66
+ const config = (0, config_1.loadProjectConfig)();
67
+ const slicePath = resolveSlicePath(config, sliceType, sliceName);
68
+ if (!dryRun && fs_extra_1.default.existsSync(slicePath)) {
69
+ logger_1.logger.error(`Already exists: ${node_path_1.default.relative(process.cwd(), slicePath)}`);
70
+ process.exit(1);
71
+ }
72
+ // Resolve templates directory (absolute path) if configured
73
+ const templatesDir = config.templates
74
+ ? node_path_1.default.resolve(process.cwd(), config.templates)
75
+ : undefined;
76
+ // Derive the bare name for use in templates (e.g. "forms/Input" → "Input")
77
+ const sliceBaseName = node_path_1.default.basename(sliceName);
78
+ const files = (0, template_resolver_1.resolveSliceFiles)(sliceType, sliceBaseName, templatesDir);
79
+ if (dryRun) {
80
+ logger_1.logger.info(`Dry run — no files will be written.`);
81
+ logger_1.logger.info(`Type: ${sliceType} (${sliceDescriptions[sliceType]})\n`);
82
+ printDryRun(slicePath + '/');
83
+ for (const relativePath of Object.keys(files)) {
84
+ printDryRun(node_path_1.default.join(slicePath, relativePath));
85
+ }
86
+ logger_1.logger.info(`\nDry run complete. Run without --dry-run to generate.`);
87
+ return;
88
+ }
89
+ // Create slice root
90
+ fs_extra_1.default.ensureDirSync(slicePath);
91
+ logger_1.logger.success(`Created: ${node_path_1.default.relative(process.cwd(), slicePath)}`);
92
+ // Write files from templates
93
+ for (const [relativePath, content] of Object.entries(files)) {
94
+ writeFile(node_path_1.default.join(slicePath, relativePath), content);
95
+ }
96
+ const source = templatesDir ? ' (custom templates)' : '';
97
+ logger_1.logger.info(`\nGenerated ${sliceType} "${sliceName}"${source}`);
98
+ logger_1.logger.info(`Structure: ${sliceDescriptions[sliceType]}`);
99
+ }
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;
@@ -0,0 +1,157 @@
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.loadProjectConfig = exports.CONFIG_FILENAMES = void 0;
7
+ exports.createStructure = createStructure;
8
+ exports.promptInitAnswers = promptInitAnswers;
9
+ exports.runInit = runInit;
10
+ exports.initCommand = initCommand;
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ const prompts_1 = require("@inquirer/prompts");
13
+ const chalk_1 = __importDefault(require("chalk"));
14
+ const fs_extra_1 = __importDefault(require("fs-extra"));
15
+ const fsd_1 = require("../../templates/fsd");
16
+ const modular_1 = require("../../templates/modular");
17
+ const config_1 = require("../../utils/config");
18
+ Object.defineProperty(exports, "CONFIG_FILENAMES", { enumerable: true, get: function () { return config_1.CONFIG_FILENAMES; } });
19
+ Object.defineProperty(exports, "loadProjectConfig", { enumerable: true, get: function () { return config_1.loadProjectConfig; } });
20
+ const logger_1 = require("../../utils/logger");
21
+ // ---------------------------------------------------------------------------
22
+ // Template registry
23
+ // ---------------------------------------------------------------------------
24
+ const templates = {
25
+ fsd: fsd_1.fsdTemplate,
26
+ modular: modular_1.modularTemplate,
27
+ };
28
+ // ---------------------------------------------------------------------------
29
+ // Architecture descriptions shown in the interactive selector
30
+ // ---------------------------------------------------------------------------
31
+ const ARCHITECTURE_DESCRIPTIONS = {
32
+ fsd: 'Feature-Sliced Design — layer-based architecture for large apps',
33
+ modular: 'Modular — module-centric architecture for medium-sized apps',
34
+ };
35
+ // ---------------------------------------------------------------------------
36
+ // Folder structure creation
37
+ // ---------------------------------------------------------------------------
38
+ /**
39
+ * Recursively creates folder structure from a FolderTree definition.
40
+ * Returns the list of created paths (relative to cwd) for summary output.
41
+ */
42
+ function createStructure(tree, basePath, cwd) {
43
+ const created = [];
44
+ for (const [folderName, children] of Object.entries(tree)) {
45
+ const folderPath = node_path_1.default.join(basePath, folderName);
46
+ fs_extra_1.default.ensureDirSync(folderPath);
47
+ created.push(node_path_1.default.relative(cwd, folderPath));
48
+ created.push(...createStructure(children, folderPath, cwd));
49
+ }
50
+ return created;
51
+ }
52
+ /**
53
+ * Runs interactive prompts to collect init parameters.
54
+ * Throws if the user cancels (Ctrl+C) — caller handles the exit.
55
+ */
56
+ async function promptInitAnswers() {
57
+ console.log(chalk_1.default.bold('\n component-forge — project initialisation\n'));
58
+ const architecture = await (0, prompts_1.select)({
59
+ message: 'Choose your architecture:',
60
+ choices: [
61
+ {
62
+ name: `${chalk_1.default.cyan('FSD')} ${chalk_1.default.gray(ARCHITECTURE_DESCRIPTIONS.fsd)}`,
63
+ value: 'fsd',
64
+ short: 'FSD',
65
+ },
66
+ {
67
+ name: `${chalk_1.default.cyan('Modular')} ${chalk_1.default.gray(ARCHITECTURE_DESCRIPTIONS.modular)}`,
68
+ value: 'modular',
69
+ short: 'Modular',
70
+ },
71
+ ],
72
+ });
73
+ const srcDir = await (0, prompts_1.input)({
74
+ message: 'Source directory:',
75
+ default: 'src',
76
+ validate: (value) => {
77
+ const trimmed = value.trim();
78
+ if (!trimmed)
79
+ return 'Source directory cannot be empty';
80
+ if (/[<>:"|?*]/.test(trimmed))
81
+ return 'Directory name contains invalid characters';
82
+ return true;
83
+ },
84
+ transformer: (value) => chalk_1.default.cyan(value),
85
+ });
86
+ const confirmed = await (0, prompts_1.confirm)({
87
+ message: `Initialise ${chalk_1.default.bold(architecture.toUpperCase())} in ${chalk_1.default.bold(`./${srcDir.trim()}`)}?`,
88
+ default: true,
89
+ });
90
+ if (!confirmed) {
91
+ logger_1.logger.info('Aborted.');
92
+ process.exit(0);
93
+ }
94
+ return { architecture, srcDir: srcDir.trim() };
95
+ }
96
+ // ---------------------------------------------------------------------------
97
+ // Core init logic — pure, no side-effects on I/O apart from FS writes
98
+ // ---------------------------------------------------------------------------
99
+ /**
100
+ * Performs the actual init: creates folder structure + writes config.
101
+ * Exported so it can be called directly (non-interactive) or from tests.
102
+ */
103
+ function runInit(architecture, srcDir, projectRoot) {
104
+ const configPath = node_path_1.default.join(projectRoot, config_1.CONFIG_FILENAMES.json);
105
+ if (fs_extra_1.default.existsSync(configPath)) {
106
+ logger_1.logger.error(`Project already initialised (${config_1.CONFIG_FILENAMES.json} exists).`);
107
+ logger_1.logger.info('Remove it or delete forge.config.ts if you want to reinitialise.');
108
+ process.exit(1);
109
+ }
110
+ logger_1.logger.info(`\nInitialising ${chalk_1.default.bold(architecture.toUpperCase())} architecture in ${chalk_1.default.cyan(`./${srcDir}`)}…\n`);
111
+ const template = templates[architecture];
112
+ // Resolve the base path for structure (respects custom srcDir)
113
+ const basePath = node_path_1.default.join(projectRoot, srcDir);
114
+ const created = createStructure(template, basePath, projectRoot);
115
+ for (const p of created) {
116
+ logger_1.logger.success(`Created: ${p}`);
117
+ }
118
+ const config = { architecture, srcDir };
119
+ (0, config_1.writeProjectConfig)(config, projectRoot);
120
+ logger_1.logger.success(`\nCreated: ${config_1.CONFIG_FILENAMES.json}`);
121
+ logger_1.logger.info(`Tip: rename to forge.config.ts for TypeScript support and IntelliSense.`);
122
+ console.log(chalk_1.default.bold(`\n ✓ ${architecture.toUpperCase()} project initialised successfully!\n`));
123
+ console.log(chalk_1.default.gray(` Next steps:\n`) +
124
+ chalk_1.default.white(` component-forge generate feature <name>\n`) +
125
+ chalk_1.default.white(` component-forge validate\n`) +
126
+ chalk_1.default.white(` component-forge check\n`));
127
+ }
128
+ // ---------------------------------------------------------------------------
129
+ // Command entry point
130
+ // ---------------------------------------------------------------------------
131
+ /**
132
+ * Called from index.ts.
133
+ * If architecture is provided — runs non-interactively (backwards-compatible).
134
+ * If omitted — runs interactive prompts.
135
+ */
136
+ function initCommand(architecture) {
137
+ if (architecture) {
138
+ // Non-interactive path — keep full backwards compatibility
139
+ runInit(architecture, 'src', process.cwd());
140
+ return;
141
+ }
142
+ // Interactive path
143
+ promptInitAnswers()
144
+ .then(({ architecture: arch, srcDir }) => {
145
+ runInit(arch, srcDir, process.cwd());
146
+ })
147
+ .catch((err) => {
148
+ // ExitPromptError is thrown when user presses Ctrl+C
149
+ const isCancel = err instanceof Error && err.name === 'ExitPromptError';
150
+ if (isCancel) {
151
+ console.log(chalk_1.default.yellow('\n Cancelled.\n'));
152
+ process.exit(0);
153
+ }
154
+ throw err;
155
+ });
156
+ }
157
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/init/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Heuristic rules for classifying existing directory names
3
+ * into their FSD / modular equivalents.
4
+ *
5
+ * Patterns are evaluated in order — first match wins.
6
+ * This file owns all classification knowledge; plan-builder.ts is pure logic.
7
+ */
8
+ export interface LayerHeuristic {
9
+ pattern: RegExp;
10
+ layer: string;
11
+ /** Optional sub-directory inside the layer, e.g. "ui" → shared/ui */
12
+ subdir?: string;
13
+ }
14
+ export declare const FSD_HEURISTICS: LayerHeuristic[];
15
+ /**
16
+ * Returns the FSD destination for a given directory name,
17
+ * or `null` if no heuristic matches.
18
+ */
19
+ export declare function classifyDir(dirName: string): {
20
+ layer: string;
21
+ subdir?: string;
22
+ } | null;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ /**
3
+ * Heuristic rules for classifying existing directory names
4
+ * into their FSD / modular equivalents.
5
+ *
6
+ * Patterns are evaluated in order — first match wins.
7
+ * This file owns all classification knowledge; plan-builder.ts is pure logic.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.FSD_HEURISTICS = void 0;
11
+ exports.classifyDir = classifyDir;
12
+ exports.FSD_HEURISTICS = [
13
+ // ── App / bootstrap ─────────────────────────────────────────────────────
14
+ { pattern: /^(app|bootstrap|main|root|providers?|router|store)$/i, layer: 'app' },
15
+ // ── Pages / routes ──────────────────────────────────────────────────────
16
+ { pattern: /^(pages?|routes?|screens?|views?)$/i, layer: 'pages' },
17
+ // ── Widgets (composite blocks) ──────────────────────────────────────────
18
+ { pattern: /^(widgets?|layouts?|containers?|blocks?)$/i, layer: 'widgets' },
19
+ // ── Features (user actions) ─────────────────────────────────────────────
20
+ { pattern: /^(features?|use-?cases?|actions?|mutations?)$/i, layer: 'features' },
21
+ // ── Entities (domain models) ────────────────────────────────────────────
22
+ { pattern: /^(entities|models?|domain|types?|interfaces?)$/i, layer: 'entities' },
23
+ // ── Shared UI ───────────────────────────────────────────────────────────
24
+ { pattern: /^(ui|components?|elements?|atoms?|molecules?)$/i, layer: 'shared', subdir: 'ui' },
25
+ // ── Shared utilities ────────────────────────────────────────────────────
26
+ { pattern: /^(utils?|helpers?|lib|libs?|common|shared)$/i, layer: 'shared' },
27
+ // ── Shared API ──────────────────────────────────────────────────────────
28
+ { pattern: /^(api|services?|http|clients?|fetchers?)$/i, layer: 'shared', subdir: 'api' },
29
+ // ── Shared hooks ────────────────────────────────────────────────────────
30
+ { pattern: /^(hooks?)$/i, layer: 'shared', subdir: 'hooks' },
31
+ // ── Shared config ───────────────────────────────────────────────────────
32
+ { pattern: /^(constants?|config|configs?|settings?)$/i, layer: 'shared', subdir: 'config' },
33
+ // ── Assets (shared but no rename needed) ────────────────────────────────
34
+ { pattern: /^(assets?|images?|icons?|fonts?|static)$/i, layer: 'shared', subdir: 'assets' },
35
+ ];
36
+ /**
37
+ * Returns the FSD destination for a given directory name,
38
+ * or `null` if no heuristic matches.
39
+ */
40
+ function classifyDir(dirName) {
41
+ for (const h of exports.FSD_HEURISTICS) {
42
+ if (h.pattern.test(dirName)) {
43
+ return { layer: h.layer, subdir: h.subdir };
44
+ }
45
+ }
46
+ return null;
47
+ }
48
+ //# sourceMappingURL=classifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classifier.js","sourceRoot":"","sources":["../../../src/commands/migrate/classifier.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAgDH,kCASC;AAhDY,QAAA,cAAc,GAAqB;IAC9C,2EAA2E;IAC3E,EAAE,OAAO,EAAE,sDAAsD,EAAE,KAAK,EAAE,KAAK,EAAE;IAEjF,2EAA2E;IAC3E,EAAE,OAAO,EAAE,qCAAqC,EAAE,KAAK,EAAE,OAAO,EAAE;IAElE,2EAA2E;IAC3E,EAAE,OAAO,EAAE,4CAA4C,EAAE,KAAK,EAAE,SAAS,EAAE;IAE3E,2EAA2E;IAC3E,EAAE,OAAO,EAAE,gDAAgD,EAAE,KAAK,EAAE,UAAU,EAAE;IAEhF,2EAA2E;IAC3E,EAAE,OAAO,EAAE,iDAAiD,EAAE,KAAK,EAAE,UAAU,EAAE;IAEjF,2EAA2E;IAC3E,EAAE,OAAO,EAAE,iDAAiD,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE;IAE7F,2EAA2E;IAC3E,EAAE,OAAO,EAAE,8CAA8C,EAAE,KAAK,EAAE,QAAQ,EAAE;IAE5E,2EAA2E;IAC3E,EAAE,OAAO,EAAE,4CAA4C,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE;IAEzF,2EAA2E;IAC3E,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;IAE5D,2EAA2E;IAC3E,EAAE,OAAO,EAAE,2CAA2C,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE;IAE3F,2EAA2E;IAC3E,EAAE,OAAO,EAAE,2CAA2C,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE;CAC5F,CAAA;AAED;;;GAGG;AACH,SAAgB,WAAW,CACzB,OAAe;IAEf,KAAK,MAAM,CAAC,IAAI,sBAAc,EAAE,CAAC;QAC/B,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAA;QAC7C,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Architecture } from '../../types/folder-tree';
2
+ export { buildMigrationPlan, scanTopLevelDirs } from './plan-builder';
3
+ export { classifyDir } from './classifier';
4
+ export type { FileMoveProposal, MigrationPlan } from './plan-builder';
5
+ /**
6
+ * CLI entry point for the migrate command.
7
+ */
8
+ export declare function migrateCommand(targetArchitecture: Architecture): void;
@@ -0,0 +1,33 @@
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.classifyDir = exports.scanTopLevelDirs = exports.buildMigrationPlan = void 0;
7
+ exports.migrateCommand = migrateCommand;
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ const config_1 = require("../../utils/config");
11
+ const logger_1 = require("../../utils/logger");
12
+ const plan_builder_1 = require("./plan-builder");
13
+ const printer_1 = require("./printer");
14
+ var plan_builder_2 = require("./plan-builder");
15
+ Object.defineProperty(exports, "buildMigrationPlan", { enumerable: true, get: function () { return plan_builder_2.buildMigrationPlan; } });
16
+ Object.defineProperty(exports, "scanTopLevelDirs", { enumerable: true, get: function () { return plan_builder_2.scanTopLevelDirs; } });
17
+ var classifier_1 = require("./classifier");
18
+ Object.defineProperty(exports, "classifyDir", { enumerable: true, get: function () { return classifier_1.classifyDir; } });
19
+ /**
20
+ * CLI entry point for the migrate command.
21
+ */
22
+ function migrateCommand(targetArchitecture) {
23
+ const config = (0, config_1.loadProjectConfig)();
24
+ if (config.architecture === targetArchitecture) {
25
+ logger_1.logger.info(`Project is already configured as ${chalk_1.default.bold(targetArchitecture.toUpperCase())}.`);
26
+ logger_1.logger.info(`Run ${chalk_1.default.cyan('component-forge validate')} to check the current structure.`);
27
+ return;
28
+ }
29
+ const srcPath = node_path_1.default.join(process.cwd(), config.srcDir);
30
+ const plan = (0, plan_builder_1.buildMigrationPlan)(srcPath, targetArchitecture);
31
+ (0, printer_1.printMigrationPlan)(plan);
32
+ }
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/migrate/index.ts"],"names":[],"mappings":";;;;;;AAkBA,wCAgBC;AAlCD,0DAA4B;AAE5B,kDAAyB;AAGzB,+CAAsD;AACtD,+CAA2C;AAE3C,iDAAmD;AACnD,uCAA8C;AAE9C,+CAAqE;AAA5D,kHAAA,kBAAkB,OAAA;AAAE,gHAAA,gBAAgB,OAAA;AAC7C,2CAA0C;AAAjC,yGAAA,WAAW,OAAA;AAGpB;;GAEG;AACH,SAAgB,cAAc,CAAC,kBAAgC;IAC7D,MAAM,MAAM,GAAG,IAAA,0BAAiB,GAAE,CAAA;IAElC,IAAI,MAAM,CAAC,YAAY,KAAK,kBAAkB,EAAE,CAAC;QAC/C,eAAM,CAAC,IAAI,CACT,oCAAoC,eAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,WAAW,EAAE,CAAC,GAAG,CACpF,CAAA;QACD,eAAM,CAAC,IAAI,CACT,OAAO,eAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,kCAAkC,CAChF,CAAA;QACD,OAAM;IACR,CAAC;IAED,MAAM,OAAO,GAAG,mBAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IACvD,MAAM,IAAI,GAAG,IAAA,iCAAkB,EAAC,OAAO,EAAE,kBAAkB,CAAC,CAAA;IAC5D,IAAA,4BAAkB,EAAC,IAAI,CAAC,CAAA;AAC1B,CAAC"}
@@ -0,0 +1 @@
1
+ export {};