@starodubenko/fsd-gen 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/README.md +61 -0
- package/cli.js +114 -0
- package/dist/config/defineConfig.d.ts +8 -0
- package/dist/config/defineConfig.d.ts.map +1 -0
- package/dist/config/defineConfig.js +8 -0
- package/dist/config/types.d.ts +98 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +9 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/lib/barrels/updateBarrels.d.ts +2 -0
- package/dist/lib/barrels/updateBarrels.d.ts.map +1 -0
- package/dist/lib/barrels/updateBarrels.js +28 -0
- package/dist/lib/config/loadConfig.d.ts +21 -0
- package/dist/lib/config/loadConfig.d.ts.map +1 -0
- package/dist/lib/config/loadConfig.js +61 -0
- package/dist/lib/config/validateConfig.d.ts +13 -0
- package/dist/lib/config/validateConfig.d.ts.map +1 -0
- package/dist/lib/config/validateConfig.js +19 -0
- package/dist/lib/constants.d.ts +113 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +129 -0
- package/dist/lib/generators/generate.d.ts +45 -0
- package/dist/lib/generators/generate.d.ts.map +1 -0
- package/dist/lib/generators/generate.js +104 -0
- package/dist/lib/generators/generatePreset.d.ts +6 -0
- package/dist/lib/generators/generatePreset.d.ts.map +1 -0
- package/dist/lib/generators/generatePreset.js +102 -0
- package/dist/lib/helpers/presetHelpers.d.ts +55 -0
- package/dist/lib/helpers/presetHelpers.d.ts.map +1 -0
- package/dist/lib/helpers/presetHelpers.js +53 -0
- package/dist/lib/naming/names.d.ts +10 -0
- package/dist/lib/naming/names.d.ts.map +1 -0
- package/dist/lib/naming/names.js +15 -0
- package/dist/lib/naming/resolvePaths.d.ts +33 -0
- package/dist/lib/naming/resolvePaths.d.ts.map +1 -0
- package/dist/lib/naming/resolvePaths.js +58 -0
- package/dist/lib/preset/actionExecution.d.ts +32 -0
- package/dist/lib/preset/actionExecution.d.ts.map +1 -0
- package/dist/lib/preset/actionExecution.js +138 -0
- package/dist/lib/preset/presetDiscovery.d.ts +40 -0
- package/dist/lib/preset/presetDiscovery.d.ts.map +1 -0
- package/dist/lib/preset/presetDiscovery.js +189 -0
- package/dist/lib/preset/presetLoading.d.ts +22 -0
- package/dist/lib/preset/presetLoading.d.ts.map +1 -0
- package/dist/lib/preset/presetLoading.js +69 -0
- package/dist/lib/routing/injectRoute.d.ts +17 -0
- package/dist/lib/routing/injectRoute.d.ts.map +1 -0
- package/dist/lib/routing/injectRoute.js +66 -0
- package/dist/lib/templates/templateLoader.d.ts +31 -0
- package/dist/lib/templates/templateLoader.d.ts.map +1 -0
- package/dist/lib/templates/templateLoader.js +122 -0
- package/package.json +64 -0
- package/templates/entity/model-ui-basic/Component.styles.ts +1 -0
- package/templates/entity/model-ui-basic/Component.tsx +18 -0
- package/templates/feature/ui-model-basic/Component.styles.ts +1 -0
- package/templates/feature/ui-model-basic/Component.tsx +17 -0
- package/templates/page/ui-basic/Component.styles.ts +1 -0
- package/templates/page/ui-basic/Component.tsx +17 -0
- package/templates/preset/table/entity/api/create/Component.tsx +19 -0
- package/templates/preset/table/entity/api/delete/Component.tsx +17 -0
- package/templates/preset/table/entity/api/get/Component.tsx +34 -0
- package/templates/preset/table/entity/api/update/Component.tsx +18 -0
- package/templates/preset/table/entity/model.ts +9 -0
- package/templates/preset/table/entity/ui/Component.tsx +11 -0
- package/templates/preset/table/feature/buttons/create/Component.styles.ts +1 -0
- package/templates/preset/table/feature/buttons/create/Component.tsx +30 -0
- package/templates/preset/table/feature/buttons/delete/Component.styles.ts +1 -0
- package/templates/preset/table/feature/buttons/delete/Component.tsx +30 -0
- package/templates/preset/table/feature/buttons/edit/Component.styles.ts +1 -0
- package/templates/preset/table/feature/buttons/edit/Component.tsx +30 -0
- package/templates/preset/table/feature/buttons.tsx +11 -0
- package/templates/preset/table/page/page/Component.tsx +19 -0
- package/templates/preset/table/page/page.tsx +19 -0
- package/templates/preset/table/widget/table/Component.tsx +50 -0
- package/templates/preset/table/widget/table.tsx +50 -0
- package/templates/shared/ui-basic/Component.styles.ts +1 -0
- package/templates/shared/ui-basic/Component.tsx +18 -0
- package/templates/widget/ui-basic/Component.styles.ts +1 -0
- package/templates/widget/ui-basic/Component.tsx +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# fsd-gen
|
|
2
|
+
|
|
3
|
+
A powerful CLI tool for scaffolding **Feature-Sliced Design (FSD)** components, slices, and layers. It automates boilerplate creation, manages dependencies, ensures consistent structure, and supports complex presets.
|
|
4
|
+
|
|
5
|
+
## 🚀 Features
|
|
6
|
+
|
|
7
|
+
- **FSD Compliance**: Automatically generates correct folder structures.
|
|
8
|
+
- **Smart Presets**: Generate entire vertical slices with one command (e.g., `preset table`).
|
|
9
|
+
- **Path Resolution**: Built-in support for FSD aliases (`@entities`, `@features`, etc.).
|
|
10
|
+
- **Interactive Mode**: User-friendly prompts for missing arguments.
|
|
11
|
+
- **Customizable**: `fsdgen.config.ts` for project-specific settings.
|
|
12
|
+
|
|
13
|
+
## 📦 Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -D @starodubenko/fsd-gen
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 🛠 Usage
|
|
20
|
+
|
|
21
|
+
### Basic Component Generation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx @starodubenko/fsd-gen generate <layer> <slice> [name]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Example:**
|
|
28
|
+
```bash
|
|
29
|
+
npx @starodubenko/fsd-gen generate entity User UserCard
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Using Presets
|
|
33
|
+
|
|
34
|
+
Presets generate multiple related components across layers.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx @starodubenko/fsd-gen preset table Product
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## ⚙️ Configuration
|
|
41
|
+
|
|
42
|
+
Create an `fsdgen.config.ts` in your project root:
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { defineConfig } from '@starodubenko/fsd-gen';
|
|
46
|
+
|
|
47
|
+
export default defineConfig({
|
|
48
|
+
rootDir: 'src',
|
|
49
|
+
aliases: {
|
|
50
|
+
'@entities': './src/entities',
|
|
51
|
+
'@features': './src/features',
|
|
52
|
+
'@widgets': './src/widgets',
|
|
53
|
+
'@pages': './src/pages',
|
|
54
|
+
'@shared': './src/shared',
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## License
|
|
60
|
+
|
|
61
|
+
MIT
|
package/cli.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { readFileSync } from 'fs';
|
|
5
|
+
import { join, dirname } from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
|
|
11
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, 'package.json'), 'utf-8'));
|
|
12
|
+
|
|
13
|
+
const program = new Command();
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.name('fsd-gen')
|
|
17
|
+
.description(pkg.description || 'FSD Component Generator')
|
|
18
|
+
.version(pkg.version);
|
|
19
|
+
|
|
20
|
+
program
|
|
21
|
+
.command('generate')
|
|
22
|
+
.alias('g')
|
|
23
|
+
.description('Generate a new FSD slice or component')
|
|
24
|
+
.argument('<layer>', 'Layer (entity, feature, widget, page, shared)')
|
|
25
|
+
.argument('<slice>', 'Slice name (or path for shared)')
|
|
26
|
+
.argument('[name]', 'Component name (optional for some layers)')
|
|
27
|
+
.action(async (layer, slice, name) => {
|
|
28
|
+
const { loadConfig } = await import('./dist/lib/config/loadConfig.js');
|
|
29
|
+
const { validateConfig } = await import('./dist/lib/config/validateConfig.js');
|
|
30
|
+
|
|
31
|
+
console.log('Loading configuration...');
|
|
32
|
+
const config = await loadConfig();
|
|
33
|
+
|
|
34
|
+
const validation = validateConfig(config);
|
|
35
|
+
if (!validation.valid) {
|
|
36
|
+
console.error('Invalid configuration:', validation.error);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log(`Generating ${layer}/${slice}/${name || ''}...`);
|
|
41
|
+
|
|
42
|
+
const { resolveFsdPaths } = await import('./dist/lib/naming/resolvePaths.js');
|
|
43
|
+
const { toPascalCase } = await import('./dist/lib/naming/names.js');
|
|
44
|
+
const { basename } = await import('path');
|
|
45
|
+
|
|
46
|
+
// If name is provided, use it.
|
|
47
|
+
// If not, derive from slice.
|
|
48
|
+
// If slice contains slashes (e.g. shared/ui/Button), take basename (Button).
|
|
49
|
+
const derivedName = name || basename(slice);
|
|
50
|
+
const componentName = toPascalCase(derivedName);
|
|
51
|
+
|
|
52
|
+
if (!validation.config || !validation.config.rootDir) {
|
|
53
|
+
throw new Error('Invalid config: rootDir missing');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const paths = resolveFsdPaths(validation.config.rootDir, layer, slice, componentName);
|
|
57
|
+
|
|
58
|
+
console.log('Paths:', JSON.stringify(paths, null, 2));
|
|
59
|
+
|
|
60
|
+
const { generateComponent } = await import('./dist/lib/generators/generate.js');
|
|
61
|
+
await generateComponent(paths, { componentName, sliceName: slice, layer });
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
program
|
|
65
|
+
.command('preset')
|
|
66
|
+
.argument('[presetName]', 'Name of the preset (e.g. table)')
|
|
67
|
+
.argument('[name]', 'Name of the entity/feature/etc')
|
|
68
|
+
.description('Generate a full vertical slice using a preset')
|
|
69
|
+
.action(async (presetName, name) => {
|
|
70
|
+
try {
|
|
71
|
+
// Load config to get templatesDir
|
|
72
|
+
const { loadConfig } = await import('./dist/lib/config/loadConfig.js');
|
|
73
|
+
const config = await loadConfig();
|
|
74
|
+
|
|
75
|
+
if (!presetName || !name) {
|
|
76
|
+
const inquirer = (await import('inquirer')).default;
|
|
77
|
+
const { listPresets } = await import('./dist/lib/templates/templateLoader.js');
|
|
78
|
+
|
|
79
|
+
const availablePresets = await listPresets(config.templatesDir);
|
|
80
|
+
|
|
81
|
+
const questions = [];
|
|
82
|
+
|
|
83
|
+
if (!presetName) {
|
|
84
|
+
questions.push({
|
|
85
|
+
type: 'list',
|
|
86
|
+
name: 'presetName',
|
|
87
|
+
message: 'Select a preset:',
|
|
88
|
+
choices: availablePresets.length > 0 ? availablePresets : ['table']
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!name) {
|
|
93
|
+
questions.push({
|
|
94
|
+
type: 'input',
|
|
95
|
+
name: 'name',
|
|
96
|
+
message: 'Enter the name (e.g. User):',
|
|
97
|
+
validate: input => input ? true : 'Name is required'
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const answers = await inquirer.prompt(questions);
|
|
102
|
+
presetName = presetName || answers.presetName;
|
|
103
|
+
name = name || answers.name;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const { generatePreset } = await import('./dist/lib/generators/generatePreset.js');
|
|
107
|
+
await generatePreset(presetName, name);
|
|
108
|
+
} catch (error) {
|
|
109
|
+
console.error('Preset generation failed:', error);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
program.parse();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FsdGenConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Define configuration for fsd-gen.
|
|
4
|
+
* @param config User configuration
|
|
5
|
+
* @returns User configuration
|
|
6
|
+
*/
|
|
7
|
+
export declare function defineConfig(config: FsdGenConfig): FsdGenConfig;
|
|
8
|
+
//# sourceMappingURL=defineConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineConfig.d.ts","sourceRoot":"","sources":["../../src/config/defineConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAE/D"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { FSD_LAYERS, NAMING_MODES, ACTION_TYPES, DISCOVERY_MODES } from '../lib/constants.js';
|
|
2
|
+
export type Layer = (typeof FSD_LAYERS)[keyof typeof FSD_LAYERS];
|
|
3
|
+
export interface FsdGenConfig {
|
|
4
|
+
/**
|
|
5
|
+
* Root directory of the source code.
|
|
6
|
+
* @default "src"
|
|
7
|
+
*/
|
|
8
|
+
rootDir?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Alias configuration.
|
|
11
|
+
* Key is the alias (e.g., "@"), value is the path relative to root (e.g., "./src").
|
|
12
|
+
*/
|
|
13
|
+
aliases?: Record<string, string>;
|
|
14
|
+
/**
|
|
15
|
+
* Directory containing custom templates.
|
|
16
|
+
* Calculated relative to the config file or process.cwd().
|
|
17
|
+
*/
|
|
18
|
+
templatesDir?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Naming convention enforcement.
|
|
21
|
+
* @default "warn"
|
|
22
|
+
*/
|
|
23
|
+
naming?: (typeof NAMING_MODES)[keyof typeof NAMING_MODES];
|
|
24
|
+
}
|
|
25
|
+
export declare const defaultConfig: FsdGenConfig;
|
|
26
|
+
export type PresetActionType = (typeof ACTION_TYPES)[keyof typeof ACTION_TYPES];
|
|
27
|
+
export interface PresetActionBase {
|
|
28
|
+
type: PresetActionType;
|
|
29
|
+
variables?: Record<string, string>;
|
|
30
|
+
}
|
|
31
|
+
export interface PresetComponentAction extends PresetActionBase {
|
|
32
|
+
type: typeof ACTION_TYPES.COMPONENT;
|
|
33
|
+
layer: Layer;
|
|
34
|
+
slice: string;
|
|
35
|
+
name?: string;
|
|
36
|
+
template: string;
|
|
37
|
+
}
|
|
38
|
+
export interface PresetFileAction extends PresetActionBase {
|
|
39
|
+
type: typeof ACTION_TYPES.FILE;
|
|
40
|
+
path: string;
|
|
41
|
+
template: string;
|
|
42
|
+
}
|
|
43
|
+
export interface PresetHookAction extends PresetActionBase {
|
|
44
|
+
type: typeof ACTION_TYPES.HOOK;
|
|
45
|
+
layer: Layer;
|
|
46
|
+
slice: string;
|
|
47
|
+
name?: string;
|
|
48
|
+
template: string;
|
|
49
|
+
}
|
|
50
|
+
export interface PresetStylesAction extends PresetActionBase {
|
|
51
|
+
type: typeof ACTION_TYPES.STYLES;
|
|
52
|
+
layer: Layer;
|
|
53
|
+
slice: string;
|
|
54
|
+
name?: string;
|
|
55
|
+
template: string;
|
|
56
|
+
}
|
|
57
|
+
export type PresetAction = PresetComponentAction | PresetFileAction | PresetHookAction | PresetStylesAction;
|
|
58
|
+
export interface ConventionConfig {
|
|
59
|
+
/** Prefix for feature slice names (e.g., 'Manage' -> 'ManageUser') */
|
|
60
|
+
featureSlicePrefix?: string;
|
|
61
|
+
/** Suffix for widget slice names (e.g., 'Table' -> 'UserTable') */
|
|
62
|
+
widgetSliceSuffix?: string;
|
|
63
|
+
/** Suffix for page slice names (e.g., 'Page' -> 'UserPage') */
|
|
64
|
+
pageSliceSuffix?: string;
|
|
65
|
+
}
|
|
66
|
+
export interface RouteConfig {
|
|
67
|
+
/** Route path (e.g., '/users', '/products/:id') */
|
|
68
|
+
path: string;
|
|
69
|
+
/** Import path for the page component (will be auto-generated if not provided) */
|
|
70
|
+
importPath?: string;
|
|
71
|
+
/** Component name (will be auto-generated from entity name if not provided) */
|
|
72
|
+
componentName?: string;
|
|
73
|
+
/** Target file for route injection (e.g., 'Router.tsx') @default "App.tsx" */
|
|
74
|
+
appFile?: string;
|
|
75
|
+
}
|
|
76
|
+
export interface PresetConfig {
|
|
77
|
+
/** Optional discovery mode ('auto' = scan directories, 'manual' = use actions array) */
|
|
78
|
+
discoveryMode?: (typeof DISCOVERY_MODES)[keyof typeof DISCOVERY_MODES];
|
|
79
|
+
/** Global variables available in all templates */
|
|
80
|
+
variables?: Record<string, string>;
|
|
81
|
+
/** Manual action definitions (required when discoveryMode is 'manual' or undefined) */
|
|
82
|
+
actions?: PresetAction[];
|
|
83
|
+
/** Convention overrides for auto-discovery mode */
|
|
84
|
+
conventions?: ConventionConfig;
|
|
85
|
+
/** Route configuration for automatic route generation */
|
|
86
|
+
routing?: RouteConfig;
|
|
87
|
+
}
|
|
88
|
+
/** Arguments passed to preset configuration function */
|
|
89
|
+
export interface PresetConfigArgs {
|
|
90
|
+
/** The entity name provided by the user (e.g., 'User', 'Product') */
|
|
91
|
+
name: string;
|
|
92
|
+
/** The loaded FSD generator configuration */
|
|
93
|
+
config: FsdGenConfig;
|
|
94
|
+
}
|
|
95
|
+
export type PresetConfigFn = (args: PresetConfigArgs) => PresetConfig;
|
|
96
|
+
export declare function definePreset(config: PresetConfig): PresetConfig;
|
|
97
|
+
export declare function definePreset(config: PresetConfigFn): PresetConfigFn;
|
|
98
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { defineConfig } from './config/defineConfig.js';
|
|
2
|
+
export { definePreset, type PresetConfig, type PresetConfigArgs, type PresetConfigFn, type FsdGenConfig, type ConventionConfig, type PresetAction } from './config/types.js';
|
|
3
|
+
export { createPresetHelpers, type PresetHelpers, type PresetHelperOptions } from './lib/helpers/presetHelpers.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC7K,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,gCAAgC,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"updateBarrels.d.ts","sourceRoot":"","sources":["../../../src/lib/barrels/updateBarrels.ts"],"names":[],"mappings":"AAWA,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAqBrF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for updating barrel (index.ts) files.
|
|
3
|
+
*
|
|
4
|
+
* Ensures that newly generated slices, segments, or components are automatically
|
|
5
|
+
* exported from their parent directories, maintaining clean import paths compliant
|
|
6
|
+
* with Feature-Sliced Design public API capability.
|
|
7
|
+
*/
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
10
|
+
import { FILE_EXTENSIONS } from '../constants.js';
|
|
11
|
+
export function updateBarrel(directory, exportName, exportPath) {
|
|
12
|
+
const indexFile = join(directory, FILE_EXTENSIONS.INDEX);
|
|
13
|
+
let content = '';
|
|
14
|
+
if (existsSync(indexFile)) {
|
|
15
|
+
content = readFileSync(indexFile, 'utf-8');
|
|
16
|
+
}
|
|
17
|
+
// Check if export already exists
|
|
18
|
+
const exportStatement = `export * from './${exportPath}';`;
|
|
19
|
+
// Or named export: export { Name } from './Path';
|
|
20
|
+
// Spec says: "Автообновление barrel-файлов ... создаёт index.ts, добавляет export, не дублирует"
|
|
21
|
+
// A simple heuristic: check if the string exists.
|
|
22
|
+
if (content.includes(exportPath)) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const newContent = content + (content.endsWith('\n') || content === '' ? '' : '\n') + exportStatement + '\n';
|
|
26
|
+
writeFileSync(indexFile, newContent);
|
|
27
|
+
console.log(`Updated ${indexFile}`);
|
|
28
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { FsdGenConfig } from '../../config/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Find the config file in the given directory
|
|
4
|
+
* @returns The config file path or null if not found
|
|
5
|
+
*/
|
|
6
|
+
export declare function findConfigFile(cwd: string): string | null;
|
|
7
|
+
/**
|
|
8
|
+
* Read and parse the config file
|
|
9
|
+
* @returns The parsed config object
|
|
10
|
+
*/
|
|
11
|
+
export declare function readConfigFile(configPath: string): Promise<Partial<FsdGenConfig>>;
|
|
12
|
+
/**
|
|
13
|
+
* Merge user config with default config
|
|
14
|
+
*/
|
|
15
|
+
export declare function mergeWithDefaults(config: Partial<FsdGenConfig>): FsdGenConfig;
|
|
16
|
+
/**
|
|
17
|
+
* Load the FSD generator configuration
|
|
18
|
+
* Orchestrates finding, reading, and merging config
|
|
19
|
+
*/
|
|
20
|
+
export declare function loadConfig(cwd?: string): Promise<FsdGenConfig>;
|
|
21
|
+
//# sourceMappingURL=loadConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadConfig.d.ts","sourceRoot":"","sources":["../../../src/lib/config/loadConfig.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,YAAY,EAAiB,MAAM,uBAAuB,CAAC;AAGpE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGzD;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CASvF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAK7E;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,YAAY,CAAC,CAcnF"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration loading logic.
|
|
3
|
+
*
|
|
4
|
+
* Responsible for finding, reading, parsing, and merging the fsd-gen configuration
|
|
5
|
+
* file (fsdgen.config.ts/js). Handles JIT compilation of TypeScript configs.
|
|
6
|
+
*/
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
import { createJiti } from 'jiti';
|
|
10
|
+
import { defaultConfig } from '../../config/types.js';
|
|
11
|
+
import { CONFIG_FILES } from '../constants.js';
|
|
12
|
+
/**
|
|
13
|
+
* Find the config file in the given directory
|
|
14
|
+
* @returns The config file path or null if not found
|
|
15
|
+
*/
|
|
16
|
+
export function findConfigFile(cwd) {
|
|
17
|
+
const configPath = join(cwd, CONFIG_FILES.FSD_GEN);
|
|
18
|
+
return existsSync(configPath) ? configPath : null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Read and parse the config file
|
|
22
|
+
* @returns The parsed config object
|
|
23
|
+
*/
|
|
24
|
+
export async function readConfigFile(configPath) {
|
|
25
|
+
try {
|
|
26
|
+
const jiti = createJiti(import.meta.url);
|
|
27
|
+
const imported = await jiti.import(configPath, { default: true });
|
|
28
|
+
return imported;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.error('Failed to load config:', error);
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Merge user config with default config
|
|
37
|
+
*/
|
|
38
|
+
export function mergeWithDefaults(config) {
|
|
39
|
+
return {
|
|
40
|
+
...defaultConfig,
|
|
41
|
+
...config,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Load the FSD generator configuration
|
|
46
|
+
* Orchestrates finding, reading, and merging config
|
|
47
|
+
*/
|
|
48
|
+
export async function loadConfig(cwd = process.cwd()) {
|
|
49
|
+
const configPath = findConfigFile(cwd);
|
|
50
|
+
if (!configPath) {
|
|
51
|
+
return defaultConfig;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const userConfig = await readConfigFile(configPath);
|
|
55
|
+
return mergeWithDefaults(userConfig);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
console.error('Failed to load config, using defaults');
|
|
59
|
+
return defaultConfig;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration validation logic.
|
|
3
|
+
*
|
|
4
|
+
* Uses Zod schemas to ensure the loaded configuration meets the required
|
|
5
|
+
* structure and constraints before the generator proceeds.
|
|
6
|
+
*/
|
|
7
|
+
import { FsdGenConfig } from '../../config/types.js';
|
|
8
|
+
export declare function validateConfig(config: unknown): {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
error?: string;
|
|
11
|
+
config?: FsdGenConfig;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=validateConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateConfig.d.ts","sourceRoot":"","sources":["../../../src/lib/config/validateConfig.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AASrD,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,CAAA;CAAE,CAczG"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const configSchema = z.object({
|
|
3
|
+
rootDir: z.string().optional(),
|
|
4
|
+
aliases: z.record(z.string(), z.string()).optional(),
|
|
5
|
+
naming: z.enum(['error', 'warn', 'autoFix']).optional(),
|
|
6
|
+
});
|
|
7
|
+
export function validateConfig(config) {
|
|
8
|
+
const result = configSchema.safeParse(config);
|
|
9
|
+
if (!result.success) {
|
|
10
|
+
return {
|
|
11
|
+
valid: false,
|
|
12
|
+
error: result.error.message
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
valid: true,
|
|
17
|
+
config: result.data
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FSD Layer names and their plural forms
|
|
3
|
+
*/
|
|
4
|
+
export declare const FSD_LAYERS: {
|
|
5
|
+
readonly ENTITY: "entity";
|
|
6
|
+
readonly FEATURE: "feature";
|
|
7
|
+
readonly WIDGET: "widget";
|
|
8
|
+
readonly PAGE: "page";
|
|
9
|
+
readonly SHARED: "shared";
|
|
10
|
+
};
|
|
11
|
+
export declare const LAYER_PLURALS: Record<string, string>;
|
|
12
|
+
/**
|
|
13
|
+
* FSD segment names (directories within slices)
|
|
14
|
+
*/
|
|
15
|
+
export declare const FSD_SEGMENTS: {
|
|
16
|
+
readonly UI: "ui";
|
|
17
|
+
readonly MODEL: "model";
|
|
18
|
+
readonly API: "api";
|
|
19
|
+
readonly LIB: "lib";
|
|
20
|
+
readonly CONFIG: "config";
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Template types for different layers
|
|
24
|
+
*/
|
|
25
|
+
export declare const DEFAULT_TEMPLATES: Record<string, string>;
|
|
26
|
+
/**
|
|
27
|
+
* File extensions
|
|
28
|
+
*/
|
|
29
|
+
export declare const FILE_EXTENSIONS: {
|
|
30
|
+
readonly TYPESCRIPT: ".ts";
|
|
31
|
+
readonly TSX: ".tsx";
|
|
32
|
+
readonly STYLES: ".styles.ts";
|
|
33
|
+
readonly JSON: ".json";
|
|
34
|
+
readonly CONFIG: "config.ts";
|
|
35
|
+
readonly INDEX: "index.ts";
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Configuration file names
|
|
39
|
+
*/
|
|
40
|
+
export declare const CONFIG_FILES: {
|
|
41
|
+
readonly FSD_GEN: "fsdgen.config.ts";
|
|
42
|
+
readonly PRESET_TS: "preset.ts";
|
|
43
|
+
readonly PRESET_JSON: "preset.json";
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Preset directory names
|
|
47
|
+
*/
|
|
48
|
+
export declare const PRESET_DIRS: {
|
|
49
|
+
readonly ROOT: "preset";
|
|
50
|
+
readonly BUTTONS: "buttons";
|
|
51
|
+
readonly TABLE: "table";
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* API hook operation names
|
|
55
|
+
*/
|
|
56
|
+
export declare const API_OPERATIONS: {
|
|
57
|
+
readonly GET: "get";
|
|
58
|
+
readonly CREATE: "create";
|
|
59
|
+
readonly UPDATE: "update";
|
|
60
|
+
readonly DELETE: "delete";
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* API hook name prefixes
|
|
64
|
+
*/
|
|
65
|
+
export declare const API_HOOK_PREFIXES: Record<string, string>;
|
|
66
|
+
/**
|
|
67
|
+
* Default fallback template
|
|
68
|
+
*/
|
|
69
|
+
export declare const DEFAULT_TEMPLATE = "ui-basic";
|
|
70
|
+
/**
|
|
71
|
+
* Default root directory
|
|
72
|
+
*/
|
|
73
|
+
export declare const DEFAULT_ROOT_DIR = "src";
|
|
74
|
+
/**
|
|
75
|
+
* Preset action types
|
|
76
|
+
*/
|
|
77
|
+
export declare const ACTION_TYPES: {
|
|
78
|
+
readonly COMPONENT: "component";
|
|
79
|
+
readonly FILE: "file";
|
|
80
|
+
readonly HOOK: "hook";
|
|
81
|
+
readonly STYLES: "styles";
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Discovery modes
|
|
85
|
+
*/
|
|
86
|
+
export declare const DISCOVERY_MODES: {
|
|
87
|
+
readonly AUTO: "auto";
|
|
88
|
+
readonly MANUAL: "manual";
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Naming convention modes
|
|
92
|
+
*/
|
|
93
|
+
export declare const NAMING_MODES: {
|
|
94
|
+
readonly ERROR: "error";
|
|
95
|
+
readonly WARN: "warn";
|
|
96
|
+
readonly AUTO_FIX: "autoFix";
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Routing configuration constants
|
|
100
|
+
*/
|
|
101
|
+
export declare const ROUTING: {
|
|
102
|
+
readonly MARKER: "{/* ROUTES_INJECTION_POINT */}";
|
|
103
|
+
readonly IMPORTS_REGEX: RegExp;
|
|
104
|
+
readonly APP_FILE: "App.tsx";
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Template file names
|
|
108
|
+
*/
|
|
109
|
+
export declare const TEMPLATE_FILES: {
|
|
110
|
+
readonly COMPONENT: "Component.tsx";
|
|
111
|
+
readonly STYLES: "Component.styles.ts";
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;CAMb,CAAC;AAEX,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMhD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;CAMf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;CAOlB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,YAAY;;;;CAIf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,WAAW;;;;CAId,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;CAKjB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAE3C;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAEtC;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;CAKf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,eAAe;;;CAGlB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,YAAY;;;;CAIf,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,OAAO;;;;CAIV,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,cAAc;;;CAGjB,CAAC"}
|