slicejs-cli 3.4.0 → 3.4.1

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.
Files changed (35) hide show
  1. package/AGENTS.md +247 -0
  2. package/client.js +63 -64
  3. package/commands/Print.js +11 -15
  4. package/commands/Validations.js +12 -23
  5. package/commands/buildProduction/buildProduction.js +23 -26
  6. package/commands/bundle/bundle.js +10 -11
  7. package/commands/createComponent/createComponent.js +14 -16
  8. package/commands/deleteComponent/deleteComponent.js +6 -6
  9. package/commands/doctor/doctor.js +11 -14
  10. package/commands/getComponent/getComponent.js +99 -162
  11. package/commands/init/init.js +25 -21
  12. package/commands/listComponents/listComponents.js +18 -21
  13. package/commands/startServer/startServer.js +21 -24
  14. package/commands/startServer/watchServer.js +7 -7
  15. package/commands/types/types.js +53 -18
  16. package/commands/utils/PathHelper.js +9 -2
  17. package/commands/utils/VersionChecker.js +3 -3
  18. package/commands/utils/bundling/DependencyAnalyzer.js +8 -16
  19. package/commands/utils/loadConfig.js +31 -0
  20. package/commands/utils/updateManager.js +3 -4
  21. package/docs/superpowers/specs/2026-05-10-pwa-generate-design.md +105 -105
  22. package/package.json +15 -3
  23. package/post.js +2 -2
  24. package/tests/bundle-generator.test.js +3 -20
  25. package/tests/component-registry-parse.test.js +34 -0
  26. package/tests/fixtures/components.js +8 -0
  27. package/tests/fixtures/sliceConfig.json +74 -0
  28. package/tests/getcomponent.test.js +407 -0
  29. package/tests/helpers/setup.js +97 -0
  30. package/tests/init-command-contract.test.js +46 -0
  31. package/tests/local-cli-delegation.test.js +7 -5
  32. package/tests/path-helper.test.js +206 -0
  33. package/tests/types-breakage.test.js +491 -0
  34. package/tests/types-generator-errors.test.js +361 -0
  35. package/tests/types-generator.test.js +172 -184
package/AGENTS.md ADDED
@@ -0,0 +1,247 @@
1
+ # Slice.js CLI — Agent Context
2
+
3
+ ## Project Structure
4
+
5
+ ```
6
+ slicejs-cli/
7
+ ├── client.js # CLI entry point (commander)
8
+ ├── commands/
9
+ │ ├── init/init.js # slice init
10
+ │ ├── startServer/startServer.js # slice dev / slice start
11
+ │ ├── build/build.js # slice build
12
+ │ ├── getComponent/getComponent.js # slice get / browse / sync
13
+ │ ├── createComponent/ # slice component create
14
+ │ ├── listComponents/ # slice component list
15
+ │ ├── deleteComponent/ # slice component delete
16
+ │ ├── doctor/doctor.js # slice doctor
17
+ │ ├── types/types.js # slice types generate
18
+ │ ├── bundle/bundle.js # bundling logic
19
+ │ ├── utils/
20
+ │ │ ├── PathHelper.js # Path resolution (critical)
21
+ │ │ ├── bundling/BundleGenerator.js
22
+ │ │ ├── updateManager.js
23
+ │ │ ├── VersionChecker.js
24
+ │ │ └── LocalCliDelegation.js
25
+ │ └── Print.js # Wrapper for console.log/error
26
+ ├── tests/
27
+ │ ├── helpers/setup.js # Shared test helper (createTestProject, withTestProject)
28
+ │ ├── fixtures/ # Minimal fixture files for tests
29
+ │ ├── bundle-generator.test.js
30
+ │ ├── bundle-v2-register-output.test.js
31
+ │ ├── client-launcher-contract.test.js
32
+ │ ├── client-update-flow-contract.test.js
33
+ │ ├── component-registry-parse.test.js
34
+ │ ├── dependency-analyzer.test.js
35
+ │ ├── init-command-contract.test.js
36
+ │ ├── local-cli-delegation.test.js
37
+ │ ├── path-helper.test.js
38
+ │ ├── postinstall-command.test.js
39
+ │ ├── types-generator.test.js
40
+ │ └── update-manager-notifications.test.js
41
+ ├── package.json # type: "module" — ES modules only
42
+ └── AGENTS.md # This file
43
+ ```
44
+
45
+ ## Testing System
46
+
47
+ ### Runner
48
+ - Uses Node.js built-in test runner: `node --test`
49
+ - Run: `npm test`
50
+ - Watch mode: `node --test --watch`
51
+
52
+ ### Shared Test Helper (`tests/helpers/setup.js`)
53
+ Three exported functions:
54
+
55
+ ```js
56
+ import { createTestProject, cleanupTestProject, withTestProject } from './helpers/setup.js';
57
+ ```
58
+
59
+ **`createTestProject(options)`** — Creates a temp directory with full Slice.js project scaffold.
60
+ - Copies real framework files from `../slice.js/` (sibling directory in monorepo)
61
+ - Falls back to `tests/fixtures/` minimal scaffold if framework not available
62
+ - Options:
63
+ - `visualComponents: ['Button']` — creates stub component files + rewrites `components.js` to include only those
64
+ - `frameworkDir` — custom framework source path
65
+ - Returns the temp directory path
66
+ - Temp dir path: `{os.tmpdir()}/slice-test-{PID}-{N}-{random}/`
67
+
68
+ **`cleanupTestProject(dir)`** — Removes the temp directory recursively.
69
+
70
+ **`withTestProject(fn, options)`** — Convenience wrapper that:
71
+ 1. Calls `createTestProject(options)`
72
+ 2. Saves and sets `process.env.INIT_CWD = dir`
73
+ 3. Runs `fn(dir)`
74
+ 4. Restores `process.env.INIT_CWD` to original value
75
+ 5. Calls `cleanupTestProject(dir)` in `finally`
76
+
77
+ ### Patterns
78
+
79
+ **For tests that need INIT_CWD pointing to the project:**
80
+ ```js
81
+ test('my test', async () => {
82
+ await withTestProject(async (tmpDir) => {
83
+ // process.env.INIT_CWD is already set to tmpDir
84
+ const result = someFunction(import.meta.url);
85
+ assert.ok(result);
86
+ });
87
+ });
88
+ ```
89
+
90
+ **For tests that pass projectRoot explicitly:**
91
+ ```js
92
+ test('my test', async () => {
93
+ const tmpRoot = await createTestProject({ visualComponents: ['Button'] });
94
+ try {
95
+ const result = await someFunction({ projectRoot: tmpRoot });
96
+ assert.equal(result, 1);
97
+ } finally {
98
+ await cleanupTestProject(tmpRoot);
99
+ }
100
+ });
101
+ ```
102
+
103
+ **For tests with shared project setup across a describe block:**
104
+ ```js
105
+ let tmpRoot;
106
+ before(async () => {
107
+ tmpRoot = await createTestProject();
108
+ process.env.INIT_CWD = tmpRoot;
109
+ });
110
+ after(async () => {
111
+ delete process.env.INIT_CWD;
112
+ await cleanupTestProject(tmpRoot);
113
+ });
114
+ ```
115
+
116
+ ### Test types
117
+
118
+ 1. **Contract tests** (`*-contract.test.js`) — Static analysis of `client.js` source code via `@babel/parser` + AST or regex. Verify command registration, option flags, and function calls. No runtime execution.
119
+ 2. **Unit tests** — Test individual functions/modules in isolation. Use temp dirs for filesystem-dependent code.
120
+ 3. **Snapshot/Integration tests** — Verify output files, generated declarations, bundle configs.
121
+
122
+ ### Rules
123
+ - No external mocking libraries (sinon, jest, etc.). Use monkey-patching + try/finally restore.
124
+ - All temp dirs MUST be cleaned up in `finally` blocks.
125
+ - `process.env.INIT_CWD` must be saved before modification and restored in `finally`.
126
+ - Dynamic `import()` is used where module caching matters, but PathHelper reads env vars at call time so cached modules work correctly.
127
+
128
+ ## PathHelper Rules (`commands/utils/PathHelper.js`)
129
+
130
+ ### Project Root Resolution
131
+ `getProjectRoot(moduleUrl)` resolves in this order:
132
+ 1. `process.env.INIT_CWD` — set by npm or by `withTestProject` during tests
133
+ 2. `process.cwd()` — current working directory
134
+ 3. `candidates(moduleUrl)` — heuristic: walk up `../../` and `../../../../` from module location, check for `src/` or `api/`
135
+
136
+ ### Functions
137
+
138
+ | Function | Returns | Notes |
139
+ |---|---|---|
140
+ | `getProjectRoot(moduleUrl)` | Resolved project root path | |
141
+ | `getSrcPath(moduleUrl, ...seg)` | `<root>/src/[...seg]` | |
142
+ | `getApiPath(moduleUrl, ...seg)` | `<root>/api/[...seg]` | |
143
+ | `getDistPath(moduleUrl, ...seg)` | `<root>/dist/[...seg]` | |
144
+ | `getPath(moduleUrl, ...seg)` | `<root>/[...seg]` | General purpose |
145
+ | `getConfigPath(moduleUrl, root?)` | `src/sliceConfig.json` | Optional explicit root param |
146
+ | `getComponentsJsPath(moduleUrl, root?)` | `src/Components/components.js` | Optional explicit root param |
147
+ | `joinRoot(root, ...seg)` | `<root>/[...seg]` | No moduleUrl needed, pure path join |
148
+
149
+ ### Critical Rules
150
+
151
+ 1. **`import.meta.url` must be passed** as first argument to all PathHelper functions (except `joinRoot`).
152
+ 2. **Explicit root parameter** (`getConfigPath`, `getComponentsJsPath`) is used by `types/types.js` when generating types for a non-cwd project. This keeps functions testable without global state.
153
+ 3. **`INIT_CWD` is the primary mechanism** for project root resolution. It's set by npm lifecycle scripts and by `withTestProject`.
154
+ 4. **`candidates()` fallback** only works when the CLI is installed inside a project that has `src/` or `api/`. This is intentionally limited.
155
+
156
+ ## Code Quality Standards
157
+
158
+ ### ES Modules Only
159
+ - `"type": "module"` in `package.json`
160
+ - Use `import`/`export` everywhere
161
+ - NO `require()`, NO `__dirname` at module scope (use `path.dirname(fileURLToPath(import.meta.url))` inline where needed)
162
+
163
+ ### No eval()
164
+ - `eval()` has been fully replaced with `JSON.parse()` for reading `components.js` files
165
+ - Components are written via `JSON.stringify()`, so content is always valid JSON
166
+ - Use `JSON.parse()` or the AST-based `ComponentRegistry` for component registry parsing
167
+
168
+ ### Error Messages
169
+ - Bare error messages (just the error message without context) must NOT be used
170
+ - Always wrap errors with context: `Print.error('Context:', error.message)`
171
+ - Use `Print.error()` / `Print.success()` / `Print.info()` / `Print.warning()` instead of raw `console.log`/`console.error`
172
+ - EXCEPTION: Formatted help/command listing output can use `console.log` directly (avoids `ℹ️ Info:` prefix pollution)
173
+
174
+ ### Empty Catch Blocks
175
+ - Silent catches are acceptable ONLY for:
176
+ - Non-critical operations (update checks, optional config reads)
177
+ - Graceful degradation paths
178
+ - All silent catches MUST have a comment explaining why: `catch { /* intentional: non-critical */ }`
179
+
180
+ ### Port Resolution (startServer)
181
+ Priority order:
182
+ 1. `--port` CLI flag (if provided by user)
183
+ 2. `config.server.port` from `sliceConfig.json`
184
+ 3. Hardcoded `3000` fallback
185
+
186
+ Commander `.option()` defaults must NOT override config values. Pass `undefined` when flag is not provided:
187
+ ```js
188
+ port: options.port ? parseInt(options.port) : undefined
189
+ ```
190
+
191
+ ### Dependency Injection for Testability
192
+ - Functions that need a project root accept it as a parameter (`projectRoot`, `root`)
193
+ - PathHelper functions that accept an explicit root param enable testing without INIT_CWD gymnastics
194
+ - Avoid reading `process.env.INIT_CWD` or `process.cwd()` directly inside business logic; use PathHelper
195
+
196
+ ## CLI Architecture (client.js)
197
+
198
+ ### Command Registration Pattern
199
+ ```js
200
+ sliceClient
201
+ .command("mycommand")
202
+ .description("...")
203
+ .option("-x, --flag <value>", "...")
204
+ .action(async (options) => {
205
+ // 1. Handle --yes / non-interactive flags before prompts
206
+ // 2. Prompt for missing required values
207
+ // 3. Delegate to command implementation
208
+ await runWithVersionCheck(async () => {
209
+ await myCommandImplementation(options);
210
+ });
211
+ });
212
+ ```
213
+
214
+ ### `runWithVersionCheck(commandFunction)`
215
+ - Wraps every command action
216
+ - Responsibilities:
217
+ 1. Fire-and-forget update notification (`notifyAvailableUpdates().catch(() => {})`)
218
+ 2. Execute the command
219
+ 3. Background version check (`checkForUpdates(false)` after 100ms delay)
220
+ - Does NOT block or prompt the user (pre-flight checks were removed)
221
+ - Errors are caught and logged via `Print.error()`
222
+
223
+ ### Init Command (`slice init`)
224
+ - Default project name: `my-slice-app`
225
+ - `-y`/`--yes [name]` flag skips interactive prompts
226
+ - Creates project directory, `chdir`s into it, sets `INIT_CWD`
227
+ - Calls `initializeProject()` from `commands/init/init.js`
228
+ - Name normalization: trim → lowercase → spaces to hyphens → strip non-alphanumeric → collapse hyphens → trim hyphens
229
+
230
+ ### Local CLI Delegation
231
+ - `maybeDelegateToLocalCli()` runs at module level before command parsing
232
+ - If a local `node_modules/slicejs-cli/` exists, spawns it instead of running the global CLI
233
+ - Controlled by `SLICE_NO_LOCAL_DELEGATION` env var
234
+
235
+ ## Visual Component Registry
236
+ - Components downloaded from GitHub: `https://raw.githubusercontent.com/VKneider/slice.js_visual_library/master/src/Components/{category}/{Name}/{file}`
237
+ - Registry URL: same base + `src/Components/components.js`
238
+ - Starter visual components on init: Button, Link, Loading, MultiRoute, Navbar, NotFound, Route
239
+ - Components are registered by writing to `src/Components/components.js`
240
+
241
+ ### File Download Rules (in `getAvailableComponents`)
242
+ - **Routing/navigation components** (`Route`, `MultiRoute`, `Link`): only `.js` file
243
+ - **Other Visual components** (Button, Loading, Navbar, etc.): `.js`, `.html`, `.css`
244
+ - **Service components** (FetchManager, etc.): only `.js` file
245
+ - File list is determined by hardcoded rules, NOT by checking the remote server
246
+ - If `.js` download fails → component install fails (fatal)
247
+ - If `.html`/`.css` fails → component install succeeds with warning
package/client.js CHANGED
@@ -13,9 +13,9 @@ import updateManager from "./commands/utils/updateManager.js";
13
13
  import fs from "fs";
14
14
  import path from "path";
15
15
  import { fileURLToPath } from "url";
16
- import { getConfigPath, getProjectRoot } from "./commands/utils/PathHelper.js";
17
- import { exec, spawnSync } from "node:child_process";
18
- import { promisify } from "util";
16
+ import { getProjectRoot, getSrcPath, getPath } from "./commands/utils/PathHelper.js";
17
+ import { loadConfigSync as sharedLoadConfigSync } from "./commands/utils/loadConfig.js";
18
+ import { spawnSync } from "node:child_process";
19
19
  import validations from "./commands/Validations.js";
20
20
  import Print from "./commands/Print.js";
21
21
  import build from './commands/build/build.js';
@@ -30,67 +30,14 @@ import {
30
30
 
31
31
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
32
32
 
33
- const loadConfig = () => {
34
- try {
35
- const configPath = getConfigPath(import.meta.url);
36
- const rawData = fs.readFileSync(configPath, "utf-8");
37
- return JSON.parse(rawData);
38
- } catch {
39
- return null;
40
- }
41
- };
42
-
43
33
  const getCategories = () => {
44
- const config = loadConfig();
34
+ const config = sharedLoadConfigSync(import.meta.url);
45
35
  return config && config.paths?.components ? Object.keys(config.paths.components) : [];
46
36
  };
47
37
 
48
38
  // Function to run version check for all commands
49
39
  async function runWithVersionCheck(commandFunction, ...args) {
50
40
  try {
51
- const execAsync = promisify(exec);
52
- await (async () => {
53
- try {
54
- const info = await updateManager.detectCliInstall();
55
- if (info && info.type === 'global') {
56
- const projectRoot = getProjectRoot(import.meta.url);
57
- const pkgPath = path.join(projectRoot, 'package.json');
58
- let hasPkg = fs.existsSync(pkgPath);
59
- if (!hasPkg) {
60
- const { confirmInit } = await inquirer.prompt([
61
- {
62
- type: 'confirm',
63
- name: 'confirmInit',
64
- message: 'No package.json found. Initialize npm in this project now?',
65
- default: true
66
- }
67
- ]);
68
- if (confirmInit) {
69
- await execAsync('npm init -y', { cwd: projectRoot });
70
- hasPkg = true;
71
- }
72
- }
73
- if (hasPkg) {
74
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
75
- const hasFramework = pkg.dependencies?.['slicejs-web-framework'];
76
- if (!hasFramework) {
77
- const { confirm } = await inquirer.prompt([
78
- {
79
- type: 'confirm',
80
- name: 'confirm',
81
- message: 'slicejs-web-framework is not installed in this project. Install it now?',
82
- default: true
83
- }
84
- ]);
85
- if (confirm) {
86
- await updateManager.updatePackage('slicejs-web-framework');
87
- }
88
- }
89
- }
90
- }
91
- } catch {}
92
- })();
93
-
94
41
  updateManager.notifyAvailableUpdates().catch(() => {});
95
42
 
96
43
  const result = await commandFunction(...args);
@@ -148,7 +95,59 @@ try {
148
95
  sliceClient
149
96
  .command("init")
150
97
  .description("Initialize a new Slice.js project")
151
- .action(async () => {
98
+ .option("-y, --yes [name]", "Skip prompts and initialize with project name")
99
+ .action(async (options) => {
100
+ let projectName = 'my-slice-app';
101
+ if (options.yes) {
102
+ projectName = typeof options.yes === 'string' ? options.yes : projectName;
103
+ } else {
104
+ const answers = await inquirer.prompt([
105
+ {
106
+ type: 'input',
107
+ name: 'projectName',
108
+ message: 'What is the name of your project?',
109
+ default: projectName,
110
+ filter: (input) => input.trim()
111
+ .toLowerCase()
112
+ .replace(/\s+/g, '-')
113
+ .replace(/[^a-z0-9-]/g, '')
114
+ .replace(/-+/g, '-')
115
+ .replace(/^-|-$/g, ''),
116
+ validate: (input) => {
117
+ if (!input || !input.trim()) return 'Project name cannot be empty';
118
+ if (input.includes('/') || input.includes('\\')) return 'Use a simple name, not a path';
119
+ return true;
120
+ }
121
+ }
122
+ ]);
123
+ projectName = answers.projectName;
124
+ }
125
+
126
+ const projectDir = path.resolve(projectName);
127
+
128
+ if (fs.existsSync(projectDir)) {
129
+ const contents = fs.readdirSync(projectDir);
130
+ if (contents.length > 0) {
131
+ const { overwrite } = await inquirer.prompt([
132
+ {
133
+ type: 'confirm',
134
+ name: 'overwrite',
135
+ message: `Directory "${answers.projectName}" already exists and is not empty. Continue?`,
136
+ default: false
137
+ }
138
+ ]);
139
+ if (!overwrite) {
140
+ Print.info('Initialization cancelled.');
141
+ return;
142
+ }
143
+ }
144
+ } else {
145
+ fs.mkdirSync(projectDir, { recursive: true });
146
+ }
147
+
148
+ process.chdir(projectDir);
149
+ process.env.INIT_CWD = projectDir;
150
+
152
151
  await runWithVersionCheck(() => {
153
152
  initializeProject();
154
153
  return Promise.resolve();
@@ -206,7 +205,7 @@ buildCommand
206
205
  sliceClient
207
206
  .command("dev")
208
207
  .description("Start development server with hot reload enabled by default")
209
- .option("-p, --port <port>", "Port for development server", 3000)
208
+ .option("-p, --port <port>", "Port for development server")
210
209
  .option("--no-hmr", "Disable hot module reload (enabled by default)")
211
210
  .action(async (options) => {
212
211
  const prevEnv = process.env.NODE_ENV;
@@ -215,7 +214,7 @@ sliceClient
215
214
  await runWithVersionCheck(async () => {
216
215
  await startServer({
217
216
  mode: 'development',
218
- port: parseInt(options.port),
217
+ port: options.port ? parseInt(options.port) : undefined,
219
218
  watch: options.hmr
220
219
  });
221
220
  });
@@ -228,7 +227,7 @@ sliceClient
228
227
  sliceClient
229
228
  .command("start")
230
229
  .description("Serve production files from dist/ (requires prior slice build)")
231
- .option("-p, --port <port>", "Port for server", 3000)
230
+ .option("-p, --port <port>", "Port for server")
232
231
  .action(async (options) => {
233
232
  const prevEnv = process.env.NODE_ENV;
234
233
  process.env.NODE_ENV = 'production';
@@ -236,7 +235,7 @@ sliceClient
236
235
  await runWithVersionCheck(async () => {
237
236
  await startServer({
238
237
  mode: 'production',
239
- port: parseInt(options.port)
238
+ port: options.port ? parseInt(options.port) : undefined
240
239
  });
241
240
  });
242
241
  } finally {
@@ -367,7 +366,7 @@ componentCommand
367
366
  }
368
367
 
369
368
  const categoryPath = config.paths.components[category].path;
370
- const fullPath = path.join(__dirname, "../../src", categoryPath);
369
+ const fullPath = getSrcPath(import.meta.url, categoryPath);
371
370
 
372
371
  if (!fs.existsSync(fullPath)) {
373
372
  Print.error(`Category path does not exist: ${categoryPath}`);
@@ -637,7 +636,7 @@ sliceClient
637
636
  });
638
637
 
639
638
 
640
- // Custom help - SIMPLIFICADO para development only
639
+ // Custom help - SIMPLIFIED for development only
641
640
  sliceClient.addHelpText('after', `
642
641
  Common Usage Examples:
643
642
  slice init - Initialize new Slice.js project
package/commands/Print.js CHANGED
@@ -43,7 +43,7 @@ export default class Print {
43
43
  console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
44
44
  }
45
45
 
46
- // Métodos para el contexto específico del CLI
46
+ // Methods for CLI-specific context
47
47
  static componentSuccess(componentName, action = 'processed') {
48
48
  console.log(chalk.green(`✅ ${componentName} ${action} successfully!`));
49
49
  }
@@ -56,12 +56,8 @@ export default class Print {
56
56
  console.log(chalk.cyan(` 📥 Downloading ${fileName}...`));
57
57
  }
58
58
 
59
- static downloadSuccess(fileName) {
60
- console.log(chalk.green(` ${fileName}`));
61
- }
62
-
63
- static downloadError(fileName, error) {
64
- console.error(chalk.red(` ❌ Error downloading ${fileName}: ${error}`));
59
+ static downloadError(fileName) {
60
+ console.error(chalk.red(` ${fileName}`));
65
61
  }
66
62
 
67
63
  static registryUpdate(message) {
@@ -93,7 +89,7 @@ export default class Print {
93
89
  Print.separator();
94
90
  }
95
91
 
96
- // Método para mostrar resultados de minificación
92
+ // Method to show minification results
97
93
  static minificationResult(filename, originalSize, minifiedSize, savingsPercent) {
98
94
  const originalKB = (originalSize / 1024).toFixed(1);
99
95
  const minifiedKB = (minifiedSize / 1024).toFixed(1);
@@ -102,12 +98,12 @@ export default class Print {
102
98
  console.log(chalk.gray(` ${originalKB}KB → ${minifiedKB}KB (${savingsPercent}% saved)`));
103
99
  }
104
100
 
105
- // Método para mostrar progreso de build
101
+ // Method to show build progress
106
102
  static buildProgress(message) {
107
103
  console.log(chalk.cyan(`🔄 ${message}`));
108
104
  }
109
105
 
110
- // Método para mostrar estadísticas de servidor
106
+ // Method to show server statistics
111
107
  static serverStats(mode, port, directory) {
112
108
  Print.newLine();
113
109
  console.log(chalk.magenta(`🌐 Server Configuration:`));
@@ -117,7 +113,7 @@ export default class Print {
117
113
  Print.newLine();
118
114
  }
119
115
 
120
- // Método para mostrar que el servidor está listo con URL destacada
116
+ // Method to show the server is ready with highlighted URL
121
117
  static serverReady(port) {
122
118
  Print.newLine();
123
119
  console.log(chalk.bgGreen.black.bold(' ✓ SERVER READY '));
@@ -129,7 +125,7 @@ export default class Print {
129
125
  Print.newLine();
130
126
  }
131
127
 
132
- // Método para mostrar el estado del servidor durante inicio
128
+ // Method to show server status during startup
133
129
  static serverStatus(status, message = '') {
134
130
  const icons = {
135
131
  checking: '🔍',
@@ -151,17 +147,17 @@ export default class Print {
151
147
  console.log(color(`${icon} ${displayMessage}`));
152
148
  }
153
149
 
154
- // Método para mostrar que se está verificando el puerto
150
+ // Method to show port checking status
155
151
  static checkingPort(port) {
156
152
  console.log(chalk.cyan(`🔍 Checking port ${port}...`));
157
153
  }
158
154
 
159
- // Nuevo: Método para debug
155
+ // New: Debug method
160
156
  static debug(message) {
161
157
  console.log(chalk.gray(`🐛 DEBUG: ${message}`));
162
158
  }
163
159
 
164
- // Nuevo: Método para logs verbosos
160
+ // New: Verbose logging method
165
161
  static verbose(message) {
166
162
  console.log(chalk.gray(`📝 ${message}`));
167
163
  }
@@ -1,9 +1,8 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import { getConfigPath, getComponentsJsPath } from './utils/PathHelper.js';
5
-
6
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
3
+ import Print from './Print.js';
4
+ import { getComponentsJsPath } from './utils/PathHelper.js';
5
+ import { loadConfigSync } from './utils/loadConfig.js';
7
6
 
8
7
  class Validations {
9
8
  constructor() {
@@ -26,25 +25,13 @@ class Validations {
26
25
  }
27
26
 
28
27
  isValidComponentName(componentName) {
29
- // Expresión regular para verificar si el nombre contiene caracteres especiales
28
+ // Regex to check if the name contains special characters
30
29
  const regex = /^[a-zA-Z][a-zA-Z0-9]*$/;
31
30
  return regex.test(componentName);
32
31
  }
33
32
 
34
33
  loadConfig() {
35
- try {
36
- const configPath = getConfigPath(import.meta.url);
37
- if (!fs.existsSync(configPath)) {
38
- // Return null silently - let commands handle missing config if needed
39
- return null;
40
- }
41
- const rawData = fs.readFileSync(configPath, 'utf-8');
42
-
43
- return JSON.parse(rawData);
44
- } catch (error) {
45
- console.error('\x1b[31m', `❌ Error loading configuration: ${error.message}`, '\x1b[0m');
46
- return null;
47
- }
34
+ return loadConfigSync(import.meta.url);
48
35
  }
49
36
 
50
37
  getCategories() {
@@ -80,19 +67,21 @@ class Validations {
80
67
  const componentFilePath = getComponentsJsPath(import.meta.url);
81
68
 
82
69
  if (!fs.existsSync(componentFilePath)) {
83
- console.error('\x1b[31m', '❌ Error: components.js not found in expected path', '\x1b[0m');
84
- console.log('\x1b[36m', 'ℹ️ Info: Run "slice component list" to generate components.js', '\x1b[0m');
70
+ Print.error('components.js not found in expected path');
71
+ Print.info('Run "slice component list" to generate components.js');
85
72
  return false;
86
73
  }
87
74
 
88
75
  const fileContent = fs.readFileSync(componentFilePath, 'utf-8');
89
- const components = eval(fileContent.replace('export default', '')); // Evalúa el contenido como objeto
76
+ const match = fileContent.match(/const components = ({[\s\S]*?});/);
77
+ if (!match) return false;
78
+ const components = JSON.parse(match[1]);
90
79
 
91
80
  return components.hasOwnProperty(componentName);
92
81
 
93
82
  } catch (error) {
94
- console.error('\x1b[31m', `❌ Error checking component existence: ${error.message}`, '\x1b[0m');
95
- console.log('\x1b[36m', 'ℹ️ Info: The components.js file may be corrupted', '\x1b[0m');
83
+ Print.error(`Error checking component existence: ${error.message}`);
84
+ Print.info('The components.js file may be corrupted');
96
85
  return false;
97
86
  }
98
87
  }