@xanahlight/component-forge 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.
- package/LICENSE +21 -0
- package/README.md +266 -0
- package/README.ru.md +219 -0
- package/dist/commands/generate.d.ts +6 -0
- package/dist/commands/generate.js +91 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/init.d.ts +10 -0
- package/dist/commands/init.js +54 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/validate.d.ts +1 -0
- package/dist/commands/validate.js +119 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/files.d.ts +8 -0
- package/dist/templates/files.js +112 -0
- package/dist/templates/files.js.map +1 -0
- package/dist/templates/fsd.d.ts +16 -0
- package/dist/templates/fsd.js +20 -0
- package/dist/templates/fsd.js.map +1 -0
- package/dist/templates/modular.d.ts +12 -0
- package/dist/templates/modular.js +16 -0
- package/dist/templates/modular.js.map +1 -0
- package/dist/types/folder-tree.d.ts +30 -0
- package/dist/types/folder-tree.js +3 -0
- package/dist/types/folder-tree.js.map +1 -0
- package/dist/utils/config.d.ts +11 -0
- package/dist/utils/config.js +33 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.js +14 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/template-resolver.d.ts +11 -0
- package/dist/utils/template-resolver.js +63 -0
- package/dist/utils/template-resolver.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,119 @@
|
|
|
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.validateCommand = validateCommand;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const config_1 = require("../utils/config");
|
|
10
|
+
const logger_1 = require("../utils/logger");
|
|
11
|
+
const layerRulesByArchitecture = {
|
|
12
|
+
fsd: {
|
|
13
|
+
required: ['app', 'shared'],
|
|
14
|
+
allowed: ['app', 'processes', 'pages', 'widgets', 'features', 'entities', 'shared'],
|
|
15
|
+
},
|
|
16
|
+
modular: {
|
|
17
|
+
required: ['shared', 'core'],
|
|
18
|
+
allowed: ['modules', 'shared', 'core'],
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Validation rules
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
/**
|
|
25
|
+
* Checks that all required layers exist under srcDir
|
|
26
|
+
*/
|
|
27
|
+
function checkRequiredLayers(srcPath, rule, srcDir) {
|
|
28
|
+
return rule.required
|
|
29
|
+
.filter((layer) => !fs_extra_1.default.existsSync(node_path_1.default.join(srcPath, layer)))
|
|
30
|
+
.map((layer) => ({
|
|
31
|
+
severity: 'error',
|
|
32
|
+
message: `Missing required layer: ${srcDir}/${layer}`,
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Checks that no unknown (forbidden) directories exist directly under srcDir
|
|
37
|
+
*/
|
|
38
|
+
function checkUnknownLayers(srcPath, rule, architecture, srcDir) {
|
|
39
|
+
if (!fs_extra_1.default.existsSync(srcPath))
|
|
40
|
+
return [];
|
|
41
|
+
return fs_extra_1.default
|
|
42
|
+
.readdirSync(srcPath, { withFileTypes: true })
|
|
43
|
+
.filter((entry) => entry.isDirectory())
|
|
44
|
+
.filter((entry) => !rule.allowed.includes(entry.name))
|
|
45
|
+
.map((entry) => ({
|
|
46
|
+
severity: 'warning',
|
|
47
|
+
message: `"${srcDir}/${entry.name}" is not a recognised layer in ${architecture.toUpperCase()} architecture`,
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Checks each slice for a public API index.ts file
|
|
52
|
+
*/
|
|
53
|
+
function checkPublicApiFiles(srcPath, rule, srcDir) {
|
|
54
|
+
const issues = [];
|
|
55
|
+
const sliceLayers = rule.allowed.filter((l) => l !== 'app' && l !== 'shared' && l !== 'core');
|
|
56
|
+
for (const layer of sliceLayers) {
|
|
57
|
+
const layerPath = node_path_1.default.join(srcPath, layer);
|
|
58
|
+
if (!fs_extra_1.default.existsSync(layerPath))
|
|
59
|
+
continue;
|
|
60
|
+
const slices = fs_extra_1.default
|
|
61
|
+
.readdirSync(layerPath, { withFileTypes: true })
|
|
62
|
+
.filter((e) => e.isDirectory());
|
|
63
|
+
for (const slice of slices) {
|
|
64
|
+
const indexPath = node_path_1.default.join(layerPath, slice.name, 'index.ts');
|
|
65
|
+
if (!fs_extra_1.default.existsSync(indexPath)) {
|
|
66
|
+
issues.push({
|
|
67
|
+
severity: 'warning',
|
|
68
|
+
message: `Missing public API: ${srcDir}/${layer}/${slice.name}/index.ts`,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return issues;
|
|
74
|
+
}
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Output formatting
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
function printIssues(issues) {
|
|
79
|
+
const errors = issues.filter((i) => i.severity === 'error');
|
|
80
|
+
const warnings = issues.filter((i) => i.severity === 'warning');
|
|
81
|
+
// Print errors first — they are blocking
|
|
82
|
+
for (const issue of errors) {
|
|
83
|
+
logger_1.logger.error(issue.message);
|
|
84
|
+
}
|
|
85
|
+
for (const issue of warnings) {
|
|
86
|
+
logger_1.logger.warning(issue.message);
|
|
87
|
+
}
|
|
88
|
+
const parts = [];
|
|
89
|
+
if (errors.length > 0)
|
|
90
|
+
parts.push(`${errors.length} error(s)`);
|
|
91
|
+
if (warnings.length > 0)
|
|
92
|
+
parts.push(`${warnings.length} warning(s)`);
|
|
93
|
+
logger_1.logger.info(`Found ${parts.join(', ')}.`);
|
|
94
|
+
}
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Command entry point
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
function validateCommand() {
|
|
99
|
+
const config = (0, config_1.loadProjectConfig)();
|
|
100
|
+
const { architecture, srcDir } = config;
|
|
101
|
+
const srcPath = node_path_1.default.join(process.cwd(), srcDir);
|
|
102
|
+
const rule = layerRulesByArchitecture[architecture];
|
|
103
|
+
logger_1.logger.info(`Validating ${architecture.toUpperCase()} architecture…`);
|
|
104
|
+
const issues = [
|
|
105
|
+
...checkRequiredLayers(srcPath, rule, srcDir),
|
|
106
|
+
...checkUnknownLayers(srcPath, rule, architecture, srcDir),
|
|
107
|
+
...checkPublicApiFiles(srcPath, rule, srcDir),
|
|
108
|
+
];
|
|
109
|
+
if (issues.length === 0) {
|
|
110
|
+
logger_1.logger.success('Architecture is valid. No issues found.');
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
printIssues(issues);
|
|
114
|
+
const hasErrors = issues.some((i) => i.severity === 'error');
|
|
115
|
+
if (hasErrors) {
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const init_1 = require("./commands/init");
|
|
6
|
+
const generate_1 = require("./commands/generate");
|
|
7
|
+
const validate_1 = require("./commands/validate");
|
|
8
|
+
const program = new commander_1.Command();
|
|
9
|
+
program
|
|
10
|
+
.name('component-forge')
|
|
11
|
+
.description('Architecture-first CLI for scalable React projects')
|
|
12
|
+
.version('0.1.0');
|
|
13
|
+
program
|
|
14
|
+
.command('init')
|
|
15
|
+
.description('Initialize project structure')
|
|
16
|
+
.argument('<architecture>', 'Architecture type (fsd | modular)', (value) => {
|
|
17
|
+
if (!['fsd', 'modular'].includes(value)) {
|
|
18
|
+
throw new Error('Architecture must be fsd or modular');
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
})
|
|
22
|
+
.action((architecture) => {
|
|
23
|
+
(0, init_1.initCommand)(architecture);
|
|
24
|
+
});
|
|
25
|
+
const SLICE_TYPES = ['feature', 'entity', 'widget', 'page', 'component', 'module'];
|
|
26
|
+
program
|
|
27
|
+
.command('generate')
|
|
28
|
+
.alias('g')
|
|
29
|
+
.description('Generate a slice or component')
|
|
30
|
+
.argument('<type>', `Slice type (${SLICE_TYPES.join(' | ')})`, (value) => {
|
|
31
|
+
if (!SLICE_TYPES.includes(value)) {
|
|
32
|
+
throw new Error(`Type must be one of: ${SLICE_TYPES.join(', ')}`);
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
})
|
|
36
|
+
.argument('<name>', 'Slice name')
|
|
37
|
+
.option('--dry-run', 'Preview files that would be generated without writing them')
|
|
38
|
+
.action((type, name, options) => {
|
|
39
|
+
(0, generate_1.generateCommand)(type, name, { dryRun: options.dryRun });
|
|
40
|
+
});
|
|
41
|
+
program
|
|
42
|
+
.command('validate')
|
|
43
|
+
.description('Validate project structure against the configured architecture')
|
|
44
|
+
.action(() => {
|
|
45
|
+
(0, validate_1.validateCommand)();
|
|
46
|
+
});
|
|
47
|
+
program.parse(process.argv);
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,yCAAmC;AAEnC,0CAA6C;AAC7C,kDAAgE;AAChE,kDAAqD;AAErD,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,iBAAiB,CAAC;KACvB,WAAW,CAAC,oDAAoD,CAAC;KACjE,OAAO,CAAC,OAAO,CAAC,CAAA;AAEnB,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,8BAA8B,CAAC;KAC3C,QAAQ,CAAC,gBAAgB,EAAE,mCAAmC,EAAE,CAAC,KAAK,EAAE,EAAE;IACzE,IAAI,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IACxD,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC,CAAC;KACD,MAAM,CAAC,CAAC,YAA+B,EAAE,EAAE;IAC1C,IAAA,kBAAW,EAAC,YAAY,CAAC,CAAA;AAC3B,CAAC,CAAC,CAAA;AAEJ,MAAM,WAAW,GAAgB,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAA;AAE/F,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,KAAK,CAAC,GAAG,CAAC;KACV,WAAW,CAAC,+BAA+B,CAAC;KAC5C,QAAQ,CAAC,QAAQ,EAAE,eAAe,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE;IACvE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAkB,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,wBAAwB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACnE,CAAC;IACD,OAAO,KAAkB,CAAA;AAC3B,CAAC,CAAC;KACD,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;KAChC,MAAM,CAAC,WAAW,EAAE,4DAA4D,CAAC;KACjF,MAAM,CAAC,CAAC,IAAe,EAAE,IAAY,EAAE,OAA6B,EAAE,EAAE;IACvE,IAAA,0BAAe,EAAC,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;AACzD,CAAC,CAAC,CAAA;AAEJ,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,gEAAgE,CAAC;KAC7E,MAAM,CAAC,GAAG,EAAE;IACX,IAAA,0BAAe,GAAE,CAAA;AACnB,CAAC,CAAC,CAAA;AAEJ,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SliceType } from '../types/folder-tree';
|
|
2
|
+
type SliceFileMap = Record<string, string>;
|
|
3
|
+
/**
|
|
4
|
+
* Returns a map of { relativeFilePath: fileContent } for a given slice type.
|
|
5
|
+
* The caller is responsible for writing these to disk.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getSliceFiles(sliceType: SliceType, name: string): SliceFileMap;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSliceFiles = getSliceFiles;
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Helpers
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
/** "auth" → "Auth", "userProfile" → "UserProfile" */
|
|
8
|
+
function toPascalCase(name) {
|
|
9
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
10
|
+
}
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Individual file templates
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
const indexTemplate = (name) => {
|
|
15
|
+
const pascal = toPascalCase(name);
|
|
16
|
+
return [
|
|
17
|
+
`export { ${pascal} } from './ui/${pascal}'`,
|
|
18
|
+
`export type { ${pascal}Props } from './ui/${pascal}'`,
|
|
19
|
+
'',
|
|
20
|
+
].join('\n');
|
|
21
|
+
};
|
|
22
|
+
const componentIndexTemplate = (name) => {
|
|
23
|
+
const pascal = toPascalCase(name);
|
|
24
|
+
return [
|
|
25
|
+
`export { ${pascal} } from './${pascal}'`,
|
|
26
|
+
`export type { ${pascal}Props } from './${pascal}'`,
|
|
27
|
+
'',
|
|
28
|
+
].join('\n');
|
|
29
|
+
};
|
|
30
|
+
const reactComponentTemplate = (name) => {
|
|
31
|
+
const pascal = toPascalCase(name);
|
|
32
|
+
return [
|
|
33
|
+
`export interface ${pascal}Props {`,
|
|
34
|
+
` // define props here`,
|
|
35
|
+
`}`,
|
|
36
|
+
``,
|
|
37
|
+
`export function ${pascal}({ ...props }: ${pascal}Props) {`,
|
|
38
|
+
` return (`,
|
|
39
|
+
` <div>`,
|
|
40
|
+
` {/* ${pascal} */}`,
|
|
41
|
+
` </div>`,
|
|
42
|
+
` )`,
|
|
43
|
+
`}`,
|
|
44
|
+
``,
|
|
45
|
+
].join('\n');
|
|
46
|
+
};
|
|
47
|
+
const modelTemplate = (name) => {
|
|
48
|
+
const pascal = toPascalCase(name);
|
|
49
|
+
return [
|
|
50
|
+
`// ${pascal} model — state, stores, hooks`,
|
|
51
|
+
``,
|
|
52
|
+
`export interface ${pascal}State {`,
|
|
53
|
+
` // define state shape here`,
|
|
54
|
+
`}`,
|
|
55
|
+
``,
|
|
56
|
+
].join('\n');
|
|
57
|
+
};
|
|
58
|
+
const apiTemplate = (name) => {
|
|
59
|
+
const pascal = toPascalCase(name);
|
|
60
|
+
return [
|
|
61
|
+
`// ${pascal} API — data fetching`,
|
|
62
|
+
``,
|
|
63
|
+
`export async function fetch${pascal}(): Promise<void> {`,
|
|
64
|
+
` // implement API call here`,
|
|
65
|
+
`}`,
|
|
66
|
+
``,
|
|
67
|
+
].join('\n');
|
|
68
|
+
};
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Slice file maps — what files get generated per slice type
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
/**
|
|
73
|
+
* Returns a map of { relativeFilePath: fileContent } for a given slice type.
|
|
74
|
+
* The caller is responsible for writing these to disk.
|
|
75
|
+
*/
|
|
76
|
+
function getSliceFiles(sliceType, name) {
|
|
77
|
+
const pascal = toPascalCase(name);
|
|
78
|
+
switch (sliceType) {
|
|
79
|
+
case 'feature':
|
|
80
|
+
case 'entity':
|
|
81
|
+
return {
|
|
82
|
+
'index.ts': indexTemplate(name),
|
|
83
|
+
[`ui/${pascal}.tsx`]: reactComponentTemplate(name),
|
|
84
|
+
'model/index.ts': modelTemplate(name),
|
|
85
|
+
'api/index.ts': apiTemplate(name),
|
|
86
|
+
};
|
|
87
|
+
case 'widget':
|
|
88
|
+
return {
|
|
89
|
+
'index.ts': indexTemplate(name),
|
|
90
|
+
[`ui/${pascal}.tsx`]: reactComponentTemplate(name),
|
|
91
|
+
'model/index.ts': modelTemplate(name),
|
|
92
|
+
};
|
|
93
|
+
case 'page':
|
|
94
|
+
return {
|
|
95
|
+
'index.ts': [`export { ${pascal}Page } from './ui/${pascal}Page'`, ''].join('\n'),
|
|
96
|
+
[`ui/${pascal}Page.tsx`]: reactComponentTemplate(`${pascal}Page`),
|
|
97
|
+
};
|
|
98
|
+
case 'component':
|
|
99
|
+
return {
|
|
100
|
+
'index.ts': componentIndexTemplate(name),
|
|
101
|
+
[`${pascal}.tsx`]: reactComponentTemplate(name),
|
|
102
|
+
};
|
|
103
|
+
case 'module':
|
|
104
|
+
return {
|
|
105
|
+
'index.ts': indexTemplate(name),
|
|
106
|
+
[`ui/${pascal}.tsx`]: reactComponentTemplate(name),
|
|
107
|
+
'model/index.ts': modelTemplate(name),
|
|
108
|
+
'api/index.ts': apiTemplate(name),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/templates/files.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fsdTemplate = void 0;
|
|
4
|
+
exports.fsdTemplate = {
|
|
5
|
+
src: {
|
|
6
|
+
app: {},
|
|
7
|
+
processes: {},
|
|
8
|
+
pages: {},
|
|
9
|
+
widgets: {},
|
|
10
|
+
features: {},
|
|
11
|
+
entities: {},
|
|
12
|
+
shared: {
|
|
13
|
+
ui: {},
|
|
14
|
+
lib: {},
|
|
15
|
+
api: {},
|
|
16
|
+
config: {},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=fsd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fsd.js","sourceRoot":"","sources":["../../src/templates/fsd.ts"],"names":[],"mappings":";;;AAAa,QAAA,WAAW,GAAG;IACzB,GAAG,EAAE;QACH,GAAG,EAAE,EAAE;QACP,SAAS,EAAE,EAAE;QACb,KAAK,EAAE,EAAE;QACT,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE,EAAE;QACZ,QAAQ,EAAE,EAAE;QACZ,MAAM,EAAE;YACN,EAAE,EAAE,EAAE;YACN,GAAG,EAAE,EAAE;YACP,GAAG,EAAE,EAAE;YACP,MAAM,EAAE,EAAE;SACX;KACF;CACF,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.modularTemplate = void 0;
|
|
4
|
+
exports.modularTemplate = {
|
|
5
|
+
src: {
|
|
6
|
+
modules: {},
|
|
7
|
+
shared: {
|
|
8
|
+
ui: {},
|
|
9
|
+
lib: {},
|
|
10
|
+
api: {},
|
|
11
|
+
config: {},
|
|
12
|
+
},
|
|
13
|
+
core: {},
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=modular.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modular.js","sourceRoot":"","sources":["../../src/templates/modular.ts"],"names":[],"mappings":";;;AAAa,QAAA,eAAe,GAAG;IAC7B,GAAG,EAAE;QACH,OAAO,EAAE,EAAE;QACX,MAAM,EAAE;YACN,EAAE,EAAE,EAAE;YACN,GAAG,EAAE,EAAE;YACP,GAAG,EAAE,EAAE;YACP,MAAM,EAAE,EAAE;SACX;QACD,IAAI,EAAE,EAAE;KACT;CACF,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type FolderTree = {
|
|
2
|
+
[key: string]: FolderTree;
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* Supported architecture strategies
|
|
6
|
+
*/
|
|
7
|
+
export type Architecture = 'fsd' | 'modular';
|
|
8
|
+
/**
|
|
9
|
+
* Supported slice / segment types per architecture
|
|
10
|
+
*/
|
|
11
|
+
export type SliceType = 'feature' | 'entity' | 'widget' | 'page' | 'component' | 'module';
|
|
12
|
+
/**
|
|
13
|
+
* Project config stored in .component-forge.json
|
|
14
|
+
*/
|
|
15
|
+
export interface ProjectConfig {
|
|
16
|
+
architecture: Architecture;
|
|
17
|
+
srcDir: string;
|
|
18
|
+
/**
|
|
19
|
+
* Optional path to a directory containing custom Handlebars (.hbs) templates.
|
|
20
|
+
* Resolved relative to the project root (where .component-forge.json lives).
|
|
21
|
+
*
|
|
22
|
+
* Directory structure must mirror the built-in layout:
|
|
23
|
+
* <templatesDir>/<sliceType>/<file>.hbs
|
|
24
|
+
*
|
|
25
|
+
* Any missing template falls back to the built-in default.
|
|
26
|
+
*
|
|
27
|
+
* @example ".forge-templates"
|
|
28
|
+
*/
|
|
29
|
+
templates?: string;
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"folder-tree.js","sourceRoot":"","sources":["../../src/types/folder-tree.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ProjectConfig } from '../types/folder-tree';
|
|
2
|
+
export declare const CONFIG_FILENAME = ".component-forge.json";
|
|
3
|
+
/**
|
|
4
|
+
* Reads and returns the project config from .component-forge.json.
|
|
5
|
+
* Exits with a user-friendly error if the file does not exist.
|
|
6
|
+
*/
|
|
7
|
+
export declare function loadProjectConfig(): ProjectConfig;
|
|
8
|
+
/**
|
|
9
|
+
* Writes the project config to .component-forge.json.
|
|
10
|
+
*/
|
|
11
|
+
export declare function writeProjectConfig(config: ProjectConfig, projectRoot: string): 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.CONFIG_FILENAME = void 0;
|
|
7
|
+
exports.loadProjectConfig = loadProjectConfig;
|
|
8
|
+
exports.writeProjectConfig = writeProjectConfig;
|
|
9
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const logger_1 = require("./logger");
|
|
12
|
+
exports.CONFIG_FILENAME = '.component-forge.json';
|
|
13
|
+
/**
|
|
14
|
+
* Reads and returns the project config from .component-forge.json.
|
|
15
|
+
* Exits with a user-friendly error if the file does not exist.
|
|
16
|
+
*/
|
|
17
|
+
function loadProjectConfig() {
|
|
18
|
+
const configPath = node_path_1.default.join(process.cwd(), exports.CONFIG_FILENAME);
|
|
19
|
+
if (!fs_extra_1.default.existsSync(configPath)) {
|
|
20
|
+
logger_1.logger.error(`No ${exports.CONFIG_FILENAME} found.`);
|
|
21
|
+
logger_1.logger.info('Run "component-forge init <architecture>" first.');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
return fs_extra_1.default.readJsonSync(configPath);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Writes the project config to .component-forge.json.
|
|
28
|
+
*/
|
|
29
|
+
function writeProjectConfig(config, projectRoot) {
|
|
30
|
+
const configPath = node_path_1.default.join(projectRoot, exports.CONFIG_FILENAME);
|
|
31
|
+
fs_extra_1.default.writeJsonSync(configPath, config, { spaces: 2 });
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":";;;;;;AAYA,8CAUC;AAKD,gDAGC;AA9BD,wDAAyB;AACzB,0DAA4B;AAG5B,qCAAiC;AAEpB,QAAA,eAAe,GAAG,uBAAuB,CAAA;AAEtD;;;GAGG;AACH,SAAgB,iBAAiB;IAC/B,MAAM,UAAU,GAAG,mBAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,uBAAe,CAAC,CAAA;IAE5D,IAAI,CAAC,kBAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,eAAM,CAAC,KAAK,CAAC,MAAM,uBAAe,SAAS,CAAC,CAAA;QAC5C,eAAM,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAA;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,OAAO,kBAAE,CAAC,YAAY,CAAC,UAAU,CAAkB,CAAA;AACrD,CAAC;AAED;;GAEG;AACH,SAAgB,kBAAkB,CAAC,MAAqB,EAAE,WAAmB;IAC3E,MAAM,UAAU,GAAG,mBAAI,CAAC,IAAI,CAAC,WAAW,EAAE,uBAAe,CAAC,CAAA;IAC1D,kBAAE,CAAC,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAA;AACrD,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
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.logger = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
exports.logger = {
|
|
9
|
+
success: (message) => console.log(chalk_1.default.green(`✅ ${message}`)),
|
|
10
|
+
error: (message) => console.error(chalk_1.default.red(`❌ ${message}`)),
|
|
11
|
+
info: (message) => console.log(chalk_1.default.blue(`ℹ️ ${message}`)),
|
|
12
|
+
warning: (message) => console.warn(chalk_1.default.yellow(`⚠️ ${message}`)),
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":";;;;;;AAAA,kDAAyB;AAEZ,QAAA,MAAM,GAAG;IACpB,OAAO,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;IAEtE,KAAK,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;IAEpE,IAAI,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC;IAEpE,OAAO,EAAE,CAAC,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,eAAK,CAAC,MAAM,CAAC,OAAO,OAAO,EAAE,CAAC,CAAC;CAC3E,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SliceType } from '../types/folder-tree';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the file map for a slice, merging custom templates over built-in defaults.
|
|
4
|
+
*
|
|
5
|
+
* @param sliceType - The type of slice being generated
|
|
6
|
+
* @param name - The raw slice name (may include path segments like "forms/Input")
|
|
7
|
+
* @param templatesDir - Absolute path to the custom templates directory (optional)
|
|
8
|
+
*
|
|
9
|
+
* @returns Record<relativeFilePath, fileContent>
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveSliceFiles(sliceType: SliceType, name: string, templatesDir?: string): Record<string, string>;
|
|
@@ -0,0 +1,63 @@
|
|
|
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.resolveSliceFiles = resolveSliceFiles;
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const handlebars_1 = __importDefault(require("handlebars"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const files_1 = require("../templates/files");
|
|
11
|
+
/** "auth" → "Auth", "userProfile" → "UserProfile" */
|
|
12
|
+
function toPascalCase(str) {
|
|
13
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Compiles a single .hbs file against the given context.
|
|
17
|
+
* Returns null if the file does not exist.
|
|
18
|
+
*/
|
|
19
|
+
function compileHbs(hbsPath, context) {
|
|
20
|
+
if (!fs_extra_1.default.existsSync(hbsPath)) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const source = fs_extra_1.default.readFileSync(hbsPath, 'utf-8');
|
|
24
|
+
const compiled = handlebars_1.default.compile(source);
|
|
25
|
+
return compiled(context);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolves the file map for a slice, merging custom templates over built-in defaults.
|
|
29
|
+
*
|
|
30
|
+
* @param sliceType - The type of slice being generated
|
|
31
|
+
* @param name - The raw slice name (may include path segments like "forms/Input")
|
|
32
|
+
* @param templatesDir - Absolute path to the custom templates directory (optional)
|
|
33
|
+
*
|
|
34
|
+
* @returns Record<relativeFilePath, fileContent>
|
|
35
|
+
*/
|
|
36
|
+
function resolveSliceFiles(sliceType, name, templatesDir) {
|
|
37
|
+
// Start with built-in defaults
|
|
38
|
+
const builtIn = (0, files_1.getSliceFiles)(sliceType, name);
|
|
39
|
+
// No custom templates configured — use built-ins as-is
|
|
40
|
+
if (!templatesDir) {
|
|
41
|
+
return builtIn;
|
|
42
|
+
}
|
|
43
|
+
const customDir = node_path_1.default.join(templatesDir, sliceType);
|
|
44
|
+
if (!fs_extra_1.default.existsSync(customDir)) {
|
|
45
|
+
return builtIn;
|
|
46
|
+
}
|
|
47
|
+
const context = {
|
|
48
|
+
name,
|
|
49
|
+
Name: toPascalCase(node_path_1.default.basename(name)),
|
|
50
|
+
sliceType,
|
|
51
|
+
};
|
|
52
|
+
// Override built-in entries with custom .hbs where available
|
|
53
|
+
const resolved = { ...builtIn };
|
|
54
|
+
for (const relPath of Object.keys(builtIn)) {
|
|
55
|
+
const hbsPath = node_path_1.default.join(customDir, `${relPath}.hbs`);
|
|
56
|
+
const customContent = compileHbs(hbsPath, context);
|
|
57
|
+
if (customContent !== null) {
|
|
58
|
+
resolved[relPath] = customContent;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return resolved;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=template-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-resolver.js","sourceRoot":"","sources":["../../src/utils/template-resolver.ts"],"names":[],"mappings":";;;;;AA8DA,8CAsCC;AApGD,wDAAyB;AACzB,4DAAmC;AACnC,0DAA4B;AAE5B,8CAAkD;AA8BlD,qDAAqD;AACrD,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AACnD,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CAAC,OAAe,EAAE,OAAwB;IAC3D,IAAI,CAAC,kBAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAA;IACb,CAAC;IAED,MAAM,MAAM,GAAG,kBAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAChD,MAAM,QAAQ,GAAG,oBAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IAC3C,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAA;AAC1B,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,iBAAiB,CAC/B,SAAoB,EACpB,IAAY,EACZ,YAAqB;IAErB,+BAA+B;IAC/B,MAAM,OAAO,GAAG,IAAA,qBAAa,EAAC,SAAS,EAAE,IAAI,CAAC,CAAA;IAE9C,uDAAuD;IACvD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,MAAM,SAAS,GAAG,mBAAI,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;IAEpD,IAAI,CAAC,kBAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,MAAM,OAAO,GAAoB;QAC/B,IAAI;QACJ,IAAI,EAAE,YAAY,CAAC,mBAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvC,SAAS;KACV,CAAA;IAED,6DAA6D;IAC7D,MAAM,QAAQ,GAA2B,EAAE,GAAG,OAAO,EAAE,CAAA;IAEvD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,mBAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,OAAO,MAAM,CAAC,CAAA;QACtD,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;QAElD,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;YAC3B,QAAQ,CAAC,OAAO,CAAC,GAAG,aAAa,CAAA;QACnC,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xanahlight/component-forge",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Architecture-first CLI for scalable React projects",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"README.md",
|
|
9
|
+
"README.ru.md",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=20.0.0"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"dev": "ts-node src/index.ts",
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"format": "prettier --write .",
|
|
20
|
+
"lint": "eslint \"src/**/*.ts\"",
|
|
21
|
+
"lint:fix": "eslint \"src/**/*.ts\" --fix"
|
|
22
|
+
},
|
|
23
|
+
"author": "vladislavprozorov",
|
|
24
|
+
"homepage": "https://github.com/vladislavprozorov/component-forge#readme",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/vladislavprozorov/component-forge.git"
|
|
28
|
+
},
|
|
29
|
+
"bin": {
|
|
30
|
+
"component-forge": "dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"keywords": [
|
|
34
|
+
"cli",
|
|
35
|
+
"react",
|
|
36
|
+
"architecture",
|
|
37
|
+
"fsd",
|
|
38
|
+
"feature-sliced-design",
|
|
39
|
+
"scaffold",
|
|
40
|
+
"generator"
|
|
41
|
+
],
|
|
42
|
+
"type": "commonjs",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"chalk": "^5.6.2",
|
|
45
|
+
"commander": "^14.0.3",
|
|
46
|
+
"fs-extra": "^11.3.3",
|
|
47
|
+
"handlebars": "^4.7.8"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/fs-extra": "^11.0.4",
|
|
51
|
+
"@types/handlebars": "^4.0.40",
|
|
52
|
+
"@types/node": "^25.3.2",
|
|
53
|
+
"eslint": "^9.39.3",
|
|
54
|
+
"eslint-config-prettier": "^10.1.8",
|
|
55
|
+
"eslint-plugin-import": "^2.32.0",
|
|
56
|
+
"prettier": "^3.8.1",
|
|
57
|
+
"ts-node": "^10.9.2",
|
|
58
|
+
"typescript": "^5.9.3",
|
|
59
|
+
"typescript-eslint": "^8.56.1"
|
|
60
|
+
}
|
|
61
|
+
}
|