@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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vladislavprozorov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,266 @@
1
+ # component-forge
2
+
3
+ 🌐 English | [Русский](README.ru.md)
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@xanahlight/component-forge.svg)](https://www.npmjs.com/package/@xanahlight/component-forge)
6
+ [![Node.js](https://img.shields.io/node/v/@xanahlight/component-forge.svg)](https://nodejs.org)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+
9
+ > Architecture-first CLI for scalable React projects.
10
+
11
+ A tool that enforces structural discipline through predefined architectural templates — Feature-Sliced Design (FSD) and Modular Architecture.
12
+
13
+ ---
14
+
15
+ ## Why
16
+
17
+ React gives you flexibility — but not structure.
18
+
19
+ In growing teams this often leads to:
20
+
21
+ - inconsistent folder structures across engineers
22
+ - unclear layer boundaries and ownership
23
+ - tight coupling between features
24
+ - architectural degradation over time
25
+
26
+ **component-forge** solves this by providing:
27
+
28
+ - standardized project structure from day one
29
+ - enforced architectural layers
30
+ - public API boundaries via `index.ts` files
31
+ - a `validate` command that catches violations before they ship
32
+
33
+ > This is not just a scaffolding tool. It is an **architecture enforcement tool**.
34
+
35
+ ---
36
+
37
+ ## Target Audience
38
+
39
+ - React teams (3–10 developers)
40
+ - Growing startups with shared codebases
41
+ - Developers who have experienced architectural chaos
42
+ - Engineers who value structure and long-term maintainability
43
+
44
+ > Not designed for beginners learning React basics.
45
+
46
+ ---
47
+
48
+ ## Supported Architectures
49
+
50
+ ### 1. Feature-Sliced Design (FSD)
51
+
52
+ Generates a layered structure:
53
+
54
+ ```
55
+ src/
56
+ ├─ app/
57
+ ├─ processes/
58
+ ├─ pages/
59
+ ├─ widgets/
60
+ ├─ features/
61
+ ├─ entities/
62
+ └─ shared/
63
+ ├─ ui/
64
+ ├─ lib/
65
+ ├─ api/
66
+ └─ config/
67
+ ```
68
+
69
+ Enforces strict layer hierarchy — app → pages → widgets → features → entities → shared.
70
+ No deep imports. Public API only via `index.ts`.
71
+
72
+ ### 2. Modular Architecture
73
+
74
+ Generates a domain-oriented structure:
75
+
76
+ ```
77
+ src/
78
+ ├─ modules/
79
+ │ ├─ auth/
80
+ │ ├─ profile/
81
+ │ └─ dashboard/
82
+ ├─ shared/
83
+ └─ core/
84
+ ```
85
+
86
+ Focused on domain separation and scalable team ownership.
87
+
88
+ ---
89
+
90
+ ## Installation
91
+
92
+ ```bash
93
+ # Global install
94
+ npm install -g @xanahlight/component-forge
95
+
96
+ # No install required (recommended for one-time setup)
97
+ npx @xanahlight/component-forge init fsd
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Commands
103
+
104
+ ### init
105
+
106
+ Creates the folder structure and writes `.component-forge.json`.
107
+
108
+ ```bash
109
+ component-forge init fsd
110
+ component-forge init modular
111
+ ```
112
+
113
+ ### generate
114
+
115
+ Generates a slice with pre-populated files.
116
+
117
+ ```bash
118
+ # FSD slices
119
+ component-forge generate feature auth
120
+ component-forge generate entity user
121
+ component-forge generate widget Header
122
+ component-forge generate page dashboard
123
+
124
+ # Components (placed in shared/ui)
125
+ component-forge generate component Button
126
+ component-forge generate component forms/Input
127
+
128
+ # Modular
129
+ component-forge generate module profile
130
+
131
+ # Short alias
132
+ component-forge g feature auth
133
+ ```
134
+
135
+ What gets generated for `generate feature auth`:
136
+
137
+ ```
138
+ src/features/auth/
139
+ ├─ index.ts <- public API
140
+ ├─ ui/Auth.tsx <- React component
141
+ ├─ model/index.ts <- state / hooks
142
+ └─ api/index.ts <- data fetching
143
+ ```
144
+
145
+ ### validate
146
+
147
+ Validates your project structure against the configured architecture.
148
+
149
+ ```bash
150
+ component-forge validate
151
+ ```
152
+
153
+ Checks:
154
+
155
+ - Required layers are present (error)
156
+ - Unknown layers that do not belong to the architecture (warning)
157
+ - Slices missing a public API `index.ts` (warning)
158
+
159
+ Exits with code `1` on errors — suitable for CI pipelines.
160
+
161
+ ---
162
+
163
+ ## Project Config
164
+
165
+ After `init`, a `.component-forge.json` is created:
166
+
167
+ ```json
168
+ {
169
+ "architecture": "fsd",
170
+ "srcDir": "src"
171
+ }
172
+ ```
173
+
174
+ All commands read this config automatically. No flags needed after init.
175
+
176
+ ---
177
+
178
+ ## Custom Templates
179
+
180
+ You can override any built-in file template with your own [Handlebars](https://handlebarsjs.com/) (`.hbs`) files.
181
+
182
+ **1. Add a `templates` field to `.component-forge.json`:**
183
+
184
+ ```json
185
+ {
186
+ "architecture": "fsd",
187
+ "srcDir": "src",
188
+ "templates": ".forge-templates"
189
+ }
190
+ ```
191
+
192
+ **2. Create `.hbs` files mirroring the built-in structure:**
193
+
194
+ ```
195
+ .forge-templates/
196
+ └─ feature/
197
+ └─ index.ts.hbs ← overrides built-in index.ts for features
198
+ ```
199
+
200
+ **Available template variables:**
201
+
202
+ | Variable | Description | Example |
203
+ | --- | --- | --- |
204
+ | `{{name}}` | Raw slice name | `auth` |
205
+ | `{{Name}}` | PascalCase name | `Auth` |
206
+ | `{{sliceType}}` | Slice type | `feature` |
207
+
208
+ **Example `.forge-templates/feature/index.ts.hbs`:**
209
+
210
+ ```handlebars
211
+ // {{sliceType}} public API
212
+ export { {{Name}} } from './ui/{{Name}}'
213
+ export type { {{Name}}Props } from './ui/{{Name}}'
214
+ ```
215
+
216
+ Any template file not found in your custom directory automatically falls back to the built-in default.
217
+
218
+ ---
219
+
220
+ ## Philosophy
221
+
222
+ - **Opinionated > Flexible** — strong defaults prevent decision fatigue
223
+ - **Structure > Freedom** — constraints enable scale
224
+ - **Predictability > Improvisation** — anyone on the team knows where things live
225
+ - **Enforcement > Convention** — `validate` catches drift before it becomes debt
226
+
227
+ ---
228
+
229
+ ## Development
230
+
231
+ ```bash
232
+ git clone https://github.com/vladislavprozorov/component-forge.git
233
+ cd component-forge
234
+ npm install
235
+ npm run build
236
+ node dist/index.js init fsd
237
+ ```
238
+
239
+ > Node.js 20+ required.
240
+
241
+ ---
242
+
243
+ ## Project Status
244
+
245
+ Active development. Core commands are functional. API may change before 1.0.
246
+
247
+ - [x] `init` — FSD and Modular scaffolding
248
+ - [x] `generate` — slices with file templates
249
+ - [x] `validate` — architecture enforcement
250
+ - [x] `generate --dry-run` — preview without writing
251
+ - [x] Custom templates via config
252
+ - [ ] VS Code extension
253
+
254
+ ---
255
+
256
+ ## Contributing
257
+
258
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
259
+
260
+ Please open an issue before submitting large changes.
261
+
262
+ ---
263
+
264
+ ## License
265
+
266
+ [MIT](LICENSE)
package/README.ru.md ADDED
@@ -0,0 +1,219 @@
1
+ # component-forge
2
+
3
+ 🌐 [English](README.md) | Русский
4
+
5
+ > CLI инструмент для масштабируемых React проектов с акцентом на архитектуру.
6
+
7
+ Инструмент, обеспечивающий структурную дисциплину через готовые архитектурные шаблоны — Feature-Sliced Design (FSD) и Модульную архитектуру.
8
+
9
+ ---
10
+
11
+ ## Зачем это нужно
12
+
13
+ React даёт гибкость — но не структуру.
14
+
15
+ В растущих командах это часто приводит к:
16
+
17
+ - непоследовательным структурам папок
18
+ - размытым границам между слоями
19
+ - тесной связанности между фичами
20
+ - архитектурной деградации со временем
21
+
22
+ **component-forge** решает это:
23
+
24
+ - стандартизированная структура проекта с первого дня
25
+ - чёткие архитектурные слои
26
+ - публичные API через файлы `index.ts`
27
+ - команда `validate` ловит нарушения до попадания в прод
28
+
29
+ > Это не просто инструмент генерации файлов. Это **инструмент контроля архитектуры**.
30
+
31
+ ---
32
+
33
+ ## Целевая аудитория
34
+
35
+ - React команды (3–10 разработчиков)
36
+ - Растущие стартапы с общей кодовой базой
37
+ - Разработчики, уже сталкивавшиеся с архитектурным хаосом
38
+ - Инженеры, ценящие структуру и долгосрочную поддерживаемость
39
+
40
+ > Не предназначен для новичков, изучающих основы React.
41
+
42
+ ---
43
+
44
+ ## Поддерживаемые архитектуры
45
+
46
+ ### 1. Feature-Sliced Design (FSD)
47
+
48
+ Генерирует слоистую структуру:
49
+
50
+ ```
51
+ src/
52
+ ├─ app/
53
+ ├─ processes/
54
+ ├─ pages/
55
+ ├─ widgets/
56
+ ├─ features/
57
+ ├─ entities/
58
+ └─ shared/
59
+ ├─ ui/
60
+ ├─ lib/
61
+ ├─ api/
62
+ └─ config/
63
+ ```
64
+
65
+ Обеспечивает строгую иерархию слоёв — app → pages → widgets → features → entities → shared.
66
+ Нет глубоких импортов. Только публичный API через `index.ts`.
67
+
68
+ ### 2. Модульная архитектура
69
+
70
+ Генерирует доменно-ориентированную структуру:
71
+
72
+ ```
73
+ src/
74
+ ├─ modules/
75
+ │ ├─ auth/
76
+ │ ├─ profile/
77
+ │ └─ dashboard/
78
+ ├─ shared/
79
+ └─ core/
80
+ ```
81
+
82
+ Фокус на разделении по доменам и масштабируемом владении кодом.
83
+
84
+ ---
85
+
86
+ ## Установка
87
+
88
+ ```bash
89
+ # Глобальная установка
90
+ npm install -g component-forge
91
+
92
+ # Без установки (рекомендуется для разового использования)
93
+ npx component-forge init fsd
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Команды
99
+
100
+ ### init
101
+
102
+ Создаёт структуру папок и записывает `.component-forge.json`.
103
+
104
+ ```bash
105
+ component-forge init fsd
106
+ component-forge init modular
107
+ ```
108
+
109
+ ### generate
110
+
111
+ Генерирует слайс с готовыми файлами.
112
+
113
+ ```bash
114
+ # FSD слайсы
115
+ component-forge generate feature auth
116
+ component-forge generate entity user
117
+ component-forge generate widget Header
118
+ component-forge generate page dashboard
119
+
120
+ # Компоненты (размещаются в shared/ui)
121
+ component-forge generate component Button
122
+ component-forge generate component forms/Input
123
+
124
+ # Модульная архитектура
125
+ component-forge generate module profile
126
+
127
+ # Короткий алиас
128
+ component-forge g feature auth
129
+ ```
130
+
131
+ Что генерируется для `generate feature auth`:
132
+
133
+ ```
134
+ src/features/auth/
135
+ ├─ index.ts <- публичный API
136
+ ├─ ui/Auth.tsx <- React компонент
137
+ ├─ model/index.ts <- состояние / хуки
138
+ └─ api/index.ts <- запросы к данным
139
+ ```
140
+
141
+ ### validate
142
+
143
+ Проверяет структуру проекта на соответствие настроенной архитектуре.
144
+
145
+ ```bash
146
+ component-forge validate
147
+ ```
148
+
149
+ Проверяет:
150
+ - Обязательные слои присутствуют (ошибка)
151
+ - Неизвестные слои, не относящиеся к архитектуре (предупреждение)
152
+ - Слайсы без публичного API `index.ts` (предупреждение)
153
+
154
+ Завершается с кодом `1` при ошибках — подходит для CI.
155
+
156
+ ---
157
+
158
+ ## Конфигурация проекта
159
+
160
+ После `init` создаётся файл `.component-forge.json`:
161
+
162
+ ```json
163
+ {
164
+ "architecture": "fsd",
165
+ "srcDir": "src"
166
+ }
167
+ ```
168
+
169
+ Все команды читают этот конфиг автоматически. Флаги после init не нужны.
170
+
171
+ ---
172
+
173
+ ## Философия
174
+
175
+ - **Мнение > Гибкость** — строгие настройки по умолчанию исключают лишние решения
176
+ - **Структура > Свобода** — ограничения обеспечивают масштабирование
177
+ - **Предсказуемость > Импровизация** — каждый в команде знает где что лежит
178
+ - **Контроль > Соглашение** — `validate` ловит отклонения до того как они становятся долгом
179
+
180
+ ---
181
+
182
+ ## Разработка
183
+
184
+ ```bash
185
+ git clone https://github.com/vladislavprozorov/component-forge.git
186
+ cd component-forge
187
+ npm install
188
+ npm run build
189
+ node dist/index.js init fsd
190
+ ```
191
+
192
+ > Требуется Node.js 20+.
193
+
194
+ ---
195
+
196
+ ## Статус проекта
197
+
198
+ Активная разработка. Основные команды работают. API может измениться до версии 1.0.
199
+
200
+ - [x] `init` — скаффолдинг FSD и Modular
201
+ - [x] `generate` — слайсы с шаблонами файлов
202
+ - [x] `validate` — контроль архитектуры
203
+ - [ ] Флаг `generate --dry-run`
204
+ - [ ] Кастомные шаблоны через конфиг
205
+ - [ ] Расширение для VS Code
206
+
207
+ ---
208
+
209
+ ## Участие в проекте
210
+
211
+ См. [CONTRIBUTING.md](CONTRIBUTING.md).
212
+
213
+ Пожалуйста, открой issue перед отправкой крупных изменений.
214
+
215
+ ---
216
+
217
+ ## Лицензия
218
+
219
+ [MIT](LICENSE)
@@ -0,0 +1,6 @@
1
+ import { SliceType } from '../types/folder-tree';
2
+ export { SliceType };
3
+ export interface GenerateOptions {
4
+ dryRun?: boolean;
5
+ }
6
+ export declare function generateCommand(sliceType: SliceType, sliceName: string, options?: GenerateOptions): void;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateCommand = generateCommand;
7
+ const 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 template_resolver_1 = require("../utils/template-resolver");
12
+ const placementByArchitecture = {
13
+ fsd: {
14
+ feature: 'features',
15
+ entity: 'entities',
16
+ widget: 'widgets',
17
+ page: 'pages',
18
+ component: 'shared/ui',
19
+ },
20
+ modular: {
21
+ module: 'modules',
22
+ component: 'shared/ui',
23
+ },
24
+ };
25
+ // ---------------------------------------------------------------------------
26
+ // Path resolution
27
+ // ---------------------------------------------------------------------------
28
+ /**
29
+ * Resolves the absolute path for the slice being generated.
30
+ * Supports nested names like "forms/Input" → src/shared/ui/forms/Input
31
+ */
32
+ function resolveSlicePath(config, sliceType, sliceName) {
33
+ const placement = placementByArchitecture[config.architecture][sliceType];
34
+ if (!placement) {
35
+ const available = Object.keys(placementByArchitecture[config.architecture]).join(', ');
36
+ logger_1.logger.error(`Slice type "${sliceType}" is not supported for ${config.architecture} architecture.`);
37
+ logger_1.logger.info(`Available types for ${config.architecture}: ${available}`);
38
+ process.exit(1);
39
+ }
40
+ return node_path_1.default.join(process.cwd(), config.srcDir, placement, sliceName);
41
+ }
42
+ // ---------------------------------------------------------------------------
43
+ // File I/O
44
+ // ---------------------------------------------------------------------------
45
+ function writeFile(filePath, content) {
46
+ fs_extra_1.default.ensureDirSync(node_path_1.default.dirname(filePath));
47
+ fs_extra_1.default.writeFileSync(filePath, content);
48
+ logger_1.logger.success(`Created: ${node_path_1.default.relative(process.cwd(), filePath)}`);
49
+ }
50
+ function printDryRun(filePath) {
51
+ logger_1.logger.info(`Would create: ${node_path_1.default.relative(process.cwd(), filePath)}`);
52
+ }
53
+ function generateCommand(sliceType, sliceName, options = {}) {
54
+ const { dryRun = false } = options;
55
+ const config = (0, config_1.loadProjectConfig)();
56
+ const slicePath = resolveSlicePath(config, sliceType, sliceName);
57
+ if (!dryRun && fs_extra_1.default.existsSync(slicePath)) {
58
+ logger_1.logger.error(`Already exists: ${node_path_1.default.relative(process.cwd(), slicePath)}`);
59
+ process.exit(1);
60
+ }
61
+ // Resolve templates directory (absolute path) if configured
62
+ const templatesDir = config.templates
63
+ ? node_path_1.default.resolve(process.cwd(), config.templates)
64
+ : undefined;
65
+ // Derive the bare name for use in templates (e.g. "forms/Input" → "Input")
66
+ const sliceBaseName = node_path_1.default.basename(sliceName);
67
+ const files = (0, template_resolver_1.resolveSliceFiles)(sliceType, sliceBaseName, templatesDir);
68
+ if (dryRun) {
69
+ logger_1.logger.info(`Dry run — no files will be written.\n`);
70
+ printDryRun(slicePath + '/');
71
+ for (const relativePath of Object.keys(files)) {
72
+ printDryRun(node_path_1.default.join(slicePath, relativePath));
73
+ }
74
+ logger_1.logger.info(`\nDry run complete. Run without --dry-run to generate.`);
75
+ return;
76
+ }
77
+ // Create slice root
78
+ fs_extra_1.default.ensureDirSync(slicePath);
79
+ logger_1.logger.success(`Created: ${node_path_1.default.relative(process.cwd(), slicePath)}`);
80
+ // Write files from templates
81
+ for (const [relativePath, content] of Object.entries(files)) {
82
+ writeFile(node_path_1.default.join(slicePath, relativePath), content);
83
+ }
84
+ if (templatesDir) {
85
+ logger_1.logger.info(`Generated ${sliceType} "${sliceName}" successfully (custom templates).`);
86
+ }
87
+ else {
88
+ logger_1.logger.info(`Generated ${sliceType} "${sliceName}" successfully.`);
89
+ }
90
+ }
91
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { Architecture } from '../types/folder-tree';
2
+ import { CONFIG_FILENAME, loadProjectConfig } from '../utils/config';
3
+ export { Architecture };
4
+ export { CONFIG_FILENAME };
5
+ /**
6
+ * Initialises the project folder structure for the given architecture
7
+ * and writes .component-forge.json so subsequent commands know the architecture.
8
+ */
9
+ export declare function initCommand(architecture: Architecture): void;
10
+ export { loadProjectConfig };
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadProjectConfig = exports.CONFIG_FILENAME = void 0;
7
+ exports.initCommand = initCommand;
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const fsd_1 = require("../templates/fsd");
11
+ const modular_1 = require("../templates/modular");
12
+ const config_1 = require("../utils/config");
13
+ Object.defineProperty(exports, "CONFIG_FILENAME", { enumerable: true, get: function () { return config_1.CONFIG_FILENAME; } });
14
+ Object.defineProperty(exports, "loadProjectConfig", { enumerable: true, get: function () { return config_1.loadProjectConfig; } });
15
+ const logger_1 = require("../utils/logger");
16
+ /**
17
+ * Template registry — maps architecture → folder tree definition
18
+ */
19
+ const templates = {
20
+ fsd: fsd_1.fsdTemplate,
21
+ modular: modular_1.modularTemplate,
22
+ };
23
+ /**
24
+ * Recursively creates folder structure from a FolderTree definition
25
+ */
26
+ function createStructure(tree, basePath) {
27
+ for (const [folderName, children] of Object.entries(tree)) {
28
+ const folderPath = node_path_1.default.join(basePath, folderName);
29
+ fs_extra_1.default.ensureDirSync(folderPath);
30
+ logger_1.logger.success(`Created: ${node_path_1.default.relative(process.cwd(), folderPath)}`);
31
+ createStructure(children, folderPath);
32
+ }
33
+ }
34
+ /**
35
+ * Initialises the project folder structure for the given architecture
36
+ * and writes .component-forge.json so subsequent commands know the architecture.
37
+ */
38
+ function initCommand(architecture) {
39
+ const template = templates[architecture];
40
+ const projectRoot = process.cwd();
41
+ const configPath = node_path_1.default.join(projectRoot, config_1.CONFIG_FILENAME);
42
+ if (fs_extra_1.default.existsSync(configPath)) {
43
+ logger_1.logger.error(`Project already initialised (${config_1.CONFIG_FILENAME} exists).`);
44
+ logger_1.logger.info('Remove it manually if you want to reinitialise.');
45
+ process.exit(1);
46
+ }
47
+ logger_1.logger.info(`Initialising ${architecture.toUpperCase()} architecture…`);
48
+ createStructure(template, projectRoot);
49
+ const config = { architecture, srcDir: 'src' };
50
+ (0, config_1.writeProjectConfig)(config, projectRoot);
51
+ logger_1.logger.success(`Created: ${config_1.CONFIG_FILENAME}`);
52
+ logger_1.logger.success('Project structure successfully created.');
53
+ }
54
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":";;;;;;AAyCA,kCAoBC;AA7DD,wDAAyB;AACzB,0DAA4B;AAE5B,0CAA8C;AAC9C,kDAAsD;AAEtD,4CAAwF;AAO/E,gGAPA,wBAAe,OAOA;AAmDf,kGA1DiB,0BAAiB,OA0DjB;AAzD1B,4CAAwC;AAQxC;;GAEG;AACH,MAAM,SAAS,GAAqC;IAClD,GAAG,EAAE,iBAAW;IAChB,OAAO,EAAE,yBAAe;CACzB,CAAA;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,IAAgB,EAAE,QAAgB;IACzD,KAAK,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1D,MAAM,UAAU,GAAG,mBAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAElD,kBAAE,CAAC,aAAa,CAAC,UAAU,CAAC,CAAA;QAC5B,eAAM,CAAC,OAAO,CAAC,YAAY,mBAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,EAAE,CAAC,CAAA;QAEtE,eAAe,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;IACvC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,YAA0B;IACpD,MAAM,QAAQ,GAAG,SAAS,CAAC,YAAY,CAAC,CAAA;IACxC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IACjC,MAAM,UAAU,GAAG,mBAAI,CAAC,IAAI,CAAC,WAAW,EAAE,wBAAe,CAAC,CAAA;IAE1D,IAAI,kBAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,eAAM,CAAC,KAAK,CAAC,gCAAgC,wBAAe,WAAW,CAAC,CAAA;QACxE,eAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAA;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,eAAM,CAAC,IAAI,CAAC,gBAAgB,YAAY,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAA;IAEvE,eAAe,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAA;IAEtC,MAAM,MAAM,GAAkB,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;IAC7D,IAAA,2BAAkB,EAAC,MAAM,EAAE,WAAW,CAAC,CAAA;IACvC,eAAM,CAAC,OAAO,CAAC,YAAY,wBAAe,EAAE,CAAC,CAAA;IAE7C,eAAM,CAAC,OAAO,CAAC,yCAAyC,CAAC,CAAA;AAC3D,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function validateCommand(): void;