@t1ep1l0t/create-fsd 1.0.2 → 2.0.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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # šŸš€ @t1ep1l0t/create-fsd
4
4
 
5
- **Scaffold modern frontend applications with Feature-Sliced Design architecture**
5
+ **Scaffold modern frontend applications with Feature-Sliced Design architecture and generate FSD structures on-the-fly**
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/@t1ep1l0t/create-fsd.svg)](https://www.npmjs.com/package/@t1ep1l0t/create-fsd)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
@@ -14,7 +14,7 @@
14
14
 
15
15
  ## šŸ“– About
16
16
 
17
- **@t1ep1l0t/create-fsd** is a powerful CLI tool that helps you quickly bootstrap production-ready React applications following the [Feature-Sliced Design (FSD)](https://feature-sliced.design/) architectural methodology. Get started with a fully configured project in seconds!
17
+ **@t1ep1l0t/create-fsd** is a powerful CLI tool that helps you quickly bootstrap production-ready React applications following the [Feature-Sliced Design (FSD)](https://feature-sliced.design/) architectural methodology. Not only can you create fully configured projects in seconds, but you can also generate FSD-compliant structures for features, entities, widgets, and pages on-demand!
18
18
 
19
19
  > šŸŽÆ Currently supports **React** template. More frameworks (Vue, Next, Nuxt, Svelte) coming soon!
20
20
 
@@ -24,8 +24,9 @@
24
24
 
25
25
  ### šŸ—ļø **Architecture**
26
26
  - **Feature-Sliced Design (FSD)** - Scalable and maintainable project structure
27
+ - **FSD Structure Generator** - Quickly generate features, entities, widgets, and pages
27
28
  - Clear separation of concerns across layers
28
- - Ready-to-use folder structure
29
+ - Ready-to-use folder structure with automated scaffolding
29
30
 
30
31
  ### ⚔ **Modern Stack**
31
32
  - **React 18** - Latest React with concurrent features
@@ -73,6 +74,68 @@ npx @t1ep1l0t/create-fsd my-app --template react
73
74
 
74
75
  ---
75
76
 
77
+ ## šŸ—ļø FSD Structure Generator
78
+
79
+ After creating your project, you can use the `fsd` command to quickly generate FSD-compliant directory structures for features, entities, widgets, and pages.
80
+
81
+ ### Usage
82
+
83
+ ```bash
84
+ create-fsd fsd [options]
85
+ ```
86
+
87
+ ### Options
88
+
89
+ | Option | Alias | Description |
90
+ |--------|-------|-------------|
91
+ | `--feature <name>` | `-f` | Create feature in `features/` |
92
+ | `--entity <name>` | `-e` | Create entity in `entities/` |
93
+ | `--widget <name>` | `-w` | Create widget in `widgets/` |
94
+ | `--page <name>` | `-p` | Create page in `pages/` |
95
+ | `--segments <segments...>` | `-s` | Segments to create (e.g., model ui api lib) |
96
+ | `--index` | `-i` | Create index files in root and all segments |
97
+
98
+ ### Examples
99
+
100
+ ```bash
101
+ # Create a feature with UI and model segments
102
+ create-fsd fsd -f user -s ui model -i
103
+
104
+ # Result:
105
+ # src/features/user/
106
+ # ā”œā”€ā”€ ui/
107
+ # │ └── index.js
108
+ # ā”œā”€ā”€ model/
109
+ # │ └── index.js
110
+ # └── index.js (exports all segments)
111
+
112
+ # Create an entity with API and lib segments
113
+ create-fsd fsd -e product -s api lib -i
114
+
115
+ # Create a widget without index files (uses .gitkeep)
116
+ create-fsd fsd -w header -s ui model
117
+
118
+ # Create a page
119
+ create-fsd fsd -p home -s ui api -i
120
+
121
+ # Add more segments to existing structure
122
+ create-fsd fsd -f user -s api config -i
123
+ # This will add api/ and config/ folders and update the root index.js
124
+ ```
125
+
126
+ ### Common Segment Names
127
+
128
+ | Segment | Purpose |
129
+ |---------|---------|
130
+ | `ui` | UI components |
131
+ | `model` | Business logic, state, hooks |
132
+ | `api` | API requests and endpoints |
133
+ | `lib` | Helper functions and utilities |
134
+ | `config` | Configuration and constants |
135
+ | `types` | TypeScript types/interfaces |
136
+
137
+ ---
138
+
76
139
  ## šŸ“‚ Project Structure
77
140
 
78
141
  The generated project follows the FSD architecture with clear layer separation:
@@ -145,19 +208,21 @@ The generated project includes working examples for all included libraries:
145
208
 
146
209
  ---
147
210
 
148
- ## šŸ“‹ CLI Options
211
+ ## šŸ“‹ CLI Commands
212
+
213
+ ### Create Project
149
214
 
150
215
  ```bash
151
216
  create-fsd <project-name> [options]
152
217
  ```
153
218
 
154
- ### Options
219
+ #### Options
155
220
 
156
221
  | Option | Alias | Description | Default |
157
222
  |--------|-------|-------------|---------|
158
223
  | `--template <name>` | `-t` | Template to use | `react` |
159
224
 
160
- ### Examples
225
+ #### Examples
161
226
 
162
227
  ```bash
163
228
  # Create project with React template (default)
@@ -170,6 +235,39 @@ npx @t1ep1l0t/create-fsd my-app --template react
170
235
  npx @t1ep1l0t/create-fsd my-app -t react
171
236
  ```
172
237
 
238
+ ### Generate FSD Structure
239
+
240
+ ```bash
241
+ create-fsd fsd [options]
242
+ ```
243
+
244
+ #### Options
245
+
246
+ | Option | Alias | Description | Required |
247
+ |--------|-------|-------------|----------|
248
+ | `--feature <name>` | `-f` | Create feature in `features/` | One layer required |
249
+ | `--entity <name>` | `-e` | Create entity in `entities/` | One layer required |
250
+ | `--widget <name>` | `-w` | Create widget in `widgets/` | One layer required |
251
+ | `--page <name>` | `-p` | Create page in `pages/` | One layer required |
252
+ | `--segments <segments...>` | `-s` | Segments to create | Yes |
253
+ | `--index` | `-i` | Create index files | No |
254
+
255
+ #### Examples
256
+
257
+ ```bash
258
+ # Create feature with index files
259
+ create-fsd fsd -f authentication -s ui model api -i
260
+
261
+ # Create entity without index files
262
+ create-fsd fsd -e user -s model api
263
+
264
+ # Create widget
265
+ create-fsd fsd -w sidebar -s ui lib -i
266
+
267
+ # Create page
268
+ create-fsd fsd -p dashboard -s ui model -i
269
+ ```
270
+
173
271
  ---
174
272
 
175
273
  ## šŸŽ“ Learn More
package/bin/cli.js CHANGED
@@ -16,7 +16,7 @@ const program = new Command();
16
16
  program
17
17
  .name('create-fsd')
18
18
  .description('CLI to create React projects with FSD architecture')
19
- .version('1.0.0')
19
+ .version('2.0.0')
20
20
  .argument('<project-name>', 'name of the project')
21
21
  .option('-t, --template <template>', 'template to use', 'react')
22
22
  .action(async (projectName, options) => {
@@ -81,4 +81,148 @@ program
81
81
  console.log();
82
82
  });
83
83
 
84
+ // FSD structure generation command
85
+ program
86
+ .command('fsd')
87
+ .description('Generate FSD (Feature-Sliced Design) structure')
88
+ .option('-f, --feature <name>', 'create feature in features/')
89
+ .option('-e, --entity <name>', 'create entity in entities/')
90
+ .option('-w, --widget <name>', 'create widget in widgets/')
91
+ .option('-p, --page <name>', 'create page in pages/')
92
+ .option('-s, --segments <segments...>', 'segments to create (e.g., model ui api lib)')
93
+ .option('-i, --index', 'create index files in root and all segments', false)
94
+ .action(async (options) => {
95
+ const { feature, entity, widget, page, segments, index } = options;
96
+
97
+ // Determine layer and name based on which flag was used
98
+ let layer, name, layerType;
99
+
100
+ if (feature) {
101
+ layer = 'features';
102
+ name = feature;
103
+ layerType = 'Feature';
104
+ } else if (entity) {
105
+ layer = 'entities';
106
+ name = entity;
107
+ layerType = 'Entity';
108
+ } else if (widget) {
109
+ layer = 'widgets';
110
+ name = widget;
111
+ layerType = 'Widget';
112
+ } else if (page) {
113
+ layer = 'pages';
114
+ name = page;
115
+ layerType = 'Page';
116
+ } else {
117
+ console.log(chalk.red('āŒ Layer flag is required! Use -f (feature), -e (entity), -w (widget), or -p (page)'));
118
+ process.exit(1);
119
+ }
120
+
121
+ // Validation
122
+ if (!segments || segments.length === 0) {
123
+ console.log(chalk.red('āŒ At least one segment is required! Use -s or --segments'));
124
+ process.exit(1);
125
+ }
126
+
127
+ console.log(chalk.blue.bold(`\nšŸ—ļø Generating FSD structure...\n`));
128
+ console.log(chalk.cyan(`Layer: ${layer}`));
129
+ console.log(chalk.cyan(`${layerType}: ${name}`));
130
+ console.log(chalk.cyan(`Segments: ${segments.join(', ')}`));
131
+ console.log(chalk.cyan(`Index files: ${index ? 'Yes' : 'No'}\n`));
132
+
133
+ const baseDir = path.join(process.cwd(), 'src', layer, name);
134
+
135
+ // Check if directory already exists
136
+ if (fs.existsSync(baseDir)) {
137
+ console.log(chalk.yellow(`āš ļø Directory ${layer}/${name} already exists!`));
138
+ console.log(chalk.yellow('Adding segments to existing structure...\n'));
139
+ }
140
+
141
+ // Create directory
142
+ fs.mkdirSync(baseDir, { recursive: true });
143
+
144
+ // Create segments
145
+ const spinner = ora('Creating segments...').start();
146
+ try {
147
+ for (const segment of segments) {
148
+ const segmentDir = path.join(baseDir, segment);
149
+ fs.mkdirSync(segmentDir, { recursive: true });
150
+
151
+ // Create index file in segment if requested
152
+ if (index) {
153
+ const segmentIndexPath = path.join(segmentDir, 'index.js');
154
+ fs.writeFileSync(segmentIndexPath, '');
155
+ } else {
156
+ // Create a .gitkeep file to ensure empty directories are tracked
157
+ const gitkeepPath = path.join(segmentDir, '.gitkeep');
158
+ fs.writeFileSync(gitkeepPath, '');
159
+ }
160
+ }
161
+ spinner.succeed('Segments created!');
162
+ } catch (error) {
163
+ spinner.fail('Failed to create segments');
164
+ console.error(error);
165
+ process.exit(1);
166
+ }
167
+
168
+ // Create index file if requested
169
+ if (index) {
170
+ const indexSpinner = ora('Creating root index file...').start();
171
+ try {
172
+ const indexPath = path.join(baseDir, 'index.js');
173
+
174
+ // If index file exists, read existing exports and merge with new ones
175
+ let existingExports = new Set();
176
+ if (fs.existsSync(indexPath)) {
177
+ const existingContent = fs.readFileSync(indexPath, 'utf-8');
178
+ const exportMatches = existingContent.matchAll(/export \* from ['"]\.\/(.+?)['"]/g);
179
+ for (const match of exportMatches) {
180
+ existingExports.add(match[1]);
181
+ }
182
+ }
183
+
184
+ // Add new segments to existing exports
185
+ segments.forEach(segment => existingExports.add(segment));
186
+
187
+ // Generate exports for all segments
188
+ let indexContent = `// ${name} exports\n\n`;
189
+
190
+ // Sort segments for consistency
191
+ const allSegments = Array.from(existingExports).sort();
192
+ for (const segment of allSegments) {
193
+ indexContent += `export * from './${segment}';\n`;
194
+ }
195
+
196
+ fs.writeFileSync(indexPath, indexContent);
197
+
198
+ if (existingExports.size > segments.length) {
199
+ indexSpinner.succeed('Root index file updated with new exports!');
200
+ } else {
201
+ indexSpinner.succeed('Root index file created!');
202
+ }
203
+ } catch (error) {
204
+ indexSpinner.fail('Failed to create root index file');
205
+ console.error(error);
206
+ process.exit(1);
207
+ }
208
+ }
209
+
210
+ // Success message
211
+ console.log(chalk.green.bold('\nāœ… FSD structure generated successfully!\n'));
212
+ console.log(chalk.cyan('Generated structure:'));
213
+ console.log(chalk.white(` src/${layer}/${name}/`));
214
+ segments.forEach((segment, idx) => {
215
+ const isLast = idx === segments.length - 1;
216
+ const prefix = index ? 'ā”œā”€ā”€' : (isLast ? '└──' : 'ā”œā”€ā”€');
217
+ console.log(chalk.white(` ${prefix} ${segment}/`));
218
+ if (index) {
219
+ console.log(chalk.white(` │ └── index.js`));
220
+ }
221
+ });
222
+ if (index) {
223
+ console.log(chalk.white(` └── index.js`));
224
+ }
225
+ console.log();
226
+ });
227
+
84
228
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t1ep1l0t/create-fsd",
3
- "version": "1.0.2",
3
+ "version": "2.0.0",
4
4
  "description": "CLI tool to create React projects with FSD architecture",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,15 @@
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ html {
6
+ font-size: 14px;
7
+ }
8
+
9
+ body {
10
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
11
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
12
+ sans-serif;
13
+ -webkit-font-smoothing: antialiased;
14
+ -moz-osx-font-smoothing: grayscale;
15
+ }
@@ -7,22 +7,3 @@
7
7
  --color-danger: #ef4444;
8
8
  --color-warning: #f59e0b;
9
9
  }
10
-
11
- * {
12
- margin: 0;
13
- padding: 0;
14
- box-sizing: border-box;
15
- }
16
-
17
- body {
18
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
19
- 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
20
- sans-serif;
21
- -webkit-font-smoothing: antialiased;
22
- -moz-osx-font-smoothing: grayscale;
23
- }
24
-
25
- code {
26
- font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
27
- monospace;
28
- }
@@ -1,11 +1,14 @@
1
- import React from 'react';
2
- import ReactDOM from 'react-dom/client';
3
- import { App } from '@app/App';
4
- import '@app/styles/index.css';
5
- import '@app/providers/i18n';
6
-
7
- ReactDOM.createRoot(document.getElementById('root')).render(
8
- <React.StrictMode>
9
- <App />
10
- </React.StrictMode>
11
- );
1
+ import React from 'react'
2
+
3
+ import ReactDOM from 'react-dom/client'
4
+
5
+ import { App } from '@app/App'
6
+ import '@app/styles/index.css'
7
+ import '@app/styles/global.css'
8
+ import '@app/providers/i18n'
9
+
10
+ ReactDOM.createRoot(document.getElementById('root')).render(
11
+ <React.StrictMode>
12
+ <App />
13
+ </React.StrictMode>
14
+ )