@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.
@@ -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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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
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,16 @@
1
+ export declare const fsdTemplate: {
2
+ src: {
3
+ app: {};
4
+ processes: {};
5
+ pages: {};
6
+ widgets: {};
7
+ features: {};
8
+ entities: {};
9
+ shared: {
10
+ ui: {};
11
+ lib: {};
12
+ api: {};
13
+ config: {};
14
+ };
15
+ };
16
+ };
@@ -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,12 @@
1
+ export declare const modularTemplate: {
2
+ src: {
3
+ modules: {};
4
+ shared: {
5
+ ui: {};
6
+ lib: {};
7
+ api: {};
8
+ config: {};
9
+ };
10
+ core: {};
11
+ };
12
+ };
@@ -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,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=folder-tree.js.map
@@ -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,6 @@
1
+ export declare const logger: {
2
+ success: (message: string) => void;
3
+ error: (message: string) => void;
4
+ info: (message: string) => void;
5
+ warning: (message: string) => void;
6
+ };
@@ -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
+ }