slicejs-cli 3.4.0 → 3.5.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/AGENTS.md +247 -0
- package/client.js +63 -64
- package/commands/Print.js +11 -15
- package/commands/Validations.js +12 -23
- package/commands/buildProduction/buildProduction.js +23 -26
- package/commands/bundle/bundle.js +10 -11
- package/commands/createComponent/createComponent.js +14 -16
- package/commands/deleteComponent/deleteComponent.js +6 -6
- package/commands/doctor/doctor.js +11 -14
- package/commands/getComponent/getComponent.js +99 -162
- package/commands/init/init.js +77 -26
- package/commands/listComponents/listComponents.js +18 -21
- package/commands/startServer/startServer.js +21 -24
- package/commands/startServer/watchServer.js +7 -7
- package/commands/types/types.js +53 -18
- package/commands/utils/PathHelper.js +9 -2
- package/commands/utils/VersionChecker.js +3 -3
- package/commands/utils/bundling/DependencyAnalyzer.js +8 -16
- package/commands/utils/loadConfig.js +31 -0
- package/commands/utils/updateManager.js +3 -4
- package/docs/superpowers/specs/2026-05-10-pwa-generate-design.md +105 -105
- package/package.json +14 -2
- package/post.js +2 -2
- package/tests/bundle-generator.test.js +3 -20
- package/tests/component-registry-parse.test.js +34 -0
- package/tests/fixtures/components.js +8 -0
- package/tests/fixtures/sliceConfig.json +74 -0
- package/tests/getcomponent.test.js +407 -0
- package/tests/helpers/setup.js +97 -0
- package/tests/init-command-contract.test.js +46 -0
- package/tests/local-cli-delegation.test.js +7 -5
- package/tests/path-helper.test.js +206 -0
- package/tests/types-breakage.test.js +491 -0
- package/tests/types-generator-errors.test.js +361 -0
- package/tests/types-generator.test.js +172 -184
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { test } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import fs from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
4
|
import path from 'node:path';
|
|
5
|
+
import { createTestProject, cleanupTestProject } from './helpers/setup.js';
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
ensureEditorConfigForTypes,
|
|
@@ -151,206 +151,194 @@ test('generateDeclarationContent creates build typing map', () => {
|
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
test('generateTypesFile creates declaration file from local components', async () => {
|
|
154
|
-
const tmpRoot =
|
|
154
|
+
const tmpRoot = await createTestProject();
|
|
155
155
|
const srcDir = path.join(tmpRoot, 'src');
|
|
156
|
-
const visualDir = path.join(srcDir, 'Components', 'Visual', 'Button');
|
|
157
|
-
const noStaticDir = path.join(srcDir, 'Components', 'Visual', 'Tabs');
|
|
158
|
-
const serviceDir = path.join(srcDir, 'Components', 'Service', 'FetchManager');
|
|
159
|
-
const outputFile = path.join(srcDir, 'slice-build.generated.d.ts');
|
|
160
156
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
157
|
+
try {
|
|
158
|
+
const visualDir = path.join(srcDir, 'Components', 'Visual', 'Button');
|
|
159
|
+
const noStaticDir = path.join(srcDir, 'Components', 'Visual', 'Tabs');
|
|
160
|
+
const serviceDir = path.join(srcDir, 'Components', 'Service', 'FetchManager');
|
|
161
|
+
const outputFile = path.join(srcDir, 'slice-build.generated.d.ts');
|
|
162
|
+
|
|
163
|
+
fs.mkdirSync(noStaticDir, { recursive: true });
|
|
164
|
+
|
|
165
|
+
fs.writeFileSync(
|
|
166
|
+
path.join(visualDir, 'Button.js'),
|
|
167
|
+
`
|
|
168
|
+
export default class Button extends HTMLElement {
|
|
169
|
+
static props = {
|
|
170
|
+
value: { type: 'string', default: 'Button', allowedValues: ['Button', 'Submit'] },
|
|
171
|
+
size: { type: 'number', allowedValues: [12, 16] },
|
|
172
|
+
disabled: { type: 'boolean', default: false }
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
`,
|
|
176
|
+
'utf8'
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
fs.writeFileSync(
|
|
180
|
+
path.join(noStaticDir, 'Tabs.js'),
|
|
181
|
+
`
|
|
182
|
+
export default class Tabs extends HTMLElement {
|
|
183
|
+
constructor() {
|
|
184
|
+
super();
|
|
174
185
|
}
|
|
175
|
-
},
|
|
176
|
-
null,
|
|
177
|
-
2
|
|
178
|
-
),
|
|
179
|
-
'utf8'
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
fs.writeFileSync(
|
|
183
|
-
path.join(srcDir, 'Components', 'components.js'),
|
|
184
|
-
`const components = {"Button": "Visual", "Tabs": "Visual", "FetchManager": "Service"};\n\nexport default components;\n`,
|
|
185
|
-
'utf8'
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
fs.writeFileSync(
|
|
189
|
-
path.join(visualDir, 'Button.js'),
|
|
190
|
-
`
|
|
191
|
-
export default class Button extends HTMLElement {
|
|
192
|
-
static props = {
|
|
193
|
-
value: { type: 'string', default: 'Button', allowedValues: ['Button', 'Submit'] },
|
|
194
|
-
size: { type: 'number', allowedValues: [12, 16] },
|
|
195
|
-
disabled: { type: 'boolean', default: false }
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
`,
|
|
199
|
-
'utf8'
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
fs.writeFileSync(
|
|
203
|
-
path.join(noStaticDir, 'Tabs.js'),
|
|
204
|
-
`
|
|
205
|
-
export default class Tabs extends HTMLElement {
|
|
206
|
-
constructor() {
|
|
207
|
-
super();
|
|
208
186
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
187
|
+
`,
|
|
188
|
+
'utf8'
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
fs.writeFileSync(
|
|
192
|
+
path.join(serviceDir, 'FetchManager.js'),
|
|
193
|
+
`
|
|
194
|
+
export default class FetchManager extends HTMLElement {
|
|
195
|
+
static props = {
|
|
196
|
+
baseUrl: { type: 'string', required: true }
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
`,
|
|
200
|
+
'utf8'
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
fs.writeFileSync(
|
|
204
|
+
path.join(srcDir, 'Components', 'components.js'),
|
|
205
|
+
'const components = {"Button": "Visual", "Tabs": "Visual", "FetchManager": "Service"};\n\nexport default components;\n',
|
|
206
|
+
'utf8'
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const result = await generateTypesFile({
|
|
210
|
+
projectRoot: tmpRoot,
|
|
211
|
+
outputPath: outputFile
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
assert.equal(result.componentsProcessed, 3);
|
|
215
|
+
assert.equal(fs.existsSync(result.outputPath), true);
|
|
216
|
+
|
|
217
|
+
const declaration = fs.readFileSync(result.outputPath, 'utf8');
|
|
218
|
+
assert.match(declaration, /export interface ButtonProps/);
|
|
219
|
+
assert.match(declaration, /value\?: 'Button' \| 'Submit';/);
|
|
220
|
+
assert.match(declaration, /size\?: 12 \| 16;/);
|
|
221
|
+
assert.match(declaration, /export interface TabsProps/);
|
|
222
|
+
assert.match(declaration, /\[key: string\]: unknown;/);
|
|
223
|
+
assert.match(declaration, /export interface FetchManagerProps/);
|
|
224
|
+
assert.match(declaration, /Tabs: TabsProps;/);
|
|
225
|
+
assert.match(declaration, /build<K extends SliceComponentName>/);
|
|
226
|
+
} finally {
|
|
227
|
+
await cleanupTestProject(tmpRoot);
|
|
228
|
+
}
|
|
243
229
|
});
|
|
244
230
|
|
|
245
231
|
test('ensureEditorConfigForTypes creates jsconfig when missing', async () => {
|
|
246
|
-
const tmpRoot =
|
|
232
|
+
const tmpRoot = await createTestProject();
|
|
247
233
|
const outputFile = path.join(tmpRoot, 'src', 'slice-build.generated.d.ts');
|
|
248
234
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
235
|
+
try {
|
|
236
|
+
fs.writeFileSync(outputFile, 'export {};\n', 'utf8');
|
|
237
|
+
|
|
238
|
+
const result = await ensureEditorConfigForTypes({
|
|
239
|
+
projectRoot: tmpRoot,
|
|
240
|
+
outputPath: outputFile
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
assert.equal(result.mode, 'created_jsconfig');
|
|
244
|
+
|
|
245
|
+
const jsconfigPath = path.join(tmpRoot, 'jsconfig.json');
|
|
246
|
+
assert.equal(fs.existsSync(jsconfigPath), true);
|
|
247
|
+
|
|
248
|
+
const jsconfig = JSON.parse(fs.readFileSync(jsconfigPath, 'utf8'));
|
|
249
|
+
assert.equal(Array.isArray(jsconfig.include), true);
|
|
250
|
+
assert.equal(jsconfig.include.includes('src/Components/**/*.js'), true);
|
|
251
|
+
assert.equal(jsconfig.include.includes('src/**/*.d.ts'), true);
|
|
252
|
+
assert.equal(jsconfig.include.includes('api/**/*.js'), false);
|
|
253
|
+
assert.equal(jsconfig.include.includes('tests/**/*.js'), false);
|
|
254
|
+
assert.equal(jsconfig.include.includes('src/**/*.js'), false);
|
|
255
|
+
assert.equal(jsconfig.compilerOptions.checkJs, true);
|
|
256
|
+
assert.equal(jsconfig.compilerOptions.strictNullChecks, false);
|
|
257
|
+
assert.equal(jsconfig.compilerOptions.noImplicitAny, false);
|
|
258
|
+
assert.equal(jsconfig.compilerOptions.strict, false);
|
|
259
|
+
assert.equal(Array.isArray(jsconfig.exclude), true);
|
|
260
|
+
assert.equal(jsconfig.exclude.includes('src/libs/**'), true);
|
|
261
|
+
assert.equal(jsconfig.exclude.includes('tests/**'), true);
|
|
262
|
+
} finally {
|
|
263
|
+
await cleanupTestProject(tmpRoot);
|
|
264
|
+
}
|
|
276
265
|
});
|
|
277
266
|
|
|
278
|
-
test('
|
|
279
|
-
const tmpRoot =
|
|
267
|
+
test('types functions use PathHelper with explicit projectRoot', async () => {
|
|
268
|
+
const tmpRoot = await createTestProject({ visualComponents: ['Button'] });
|
|
280
269
|
const srcDir = path.join(tmpRoot, 'src');
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
assert.equal(result.scannedFiles, 2);
|
|
308
|
-
assert.equal(result.updatedFiles, 1);
|
|
309
|
-
assert.equal(fs.readFileSync(vendorA, 'utf8').startsWith('// @ts-nocheck\n'), true);
|
|
310
|
-
assert.equal(fs.readFileSync(vendorB, 'utf8').startsWith('// @ts-nocheck\n'), true);
|
|
270
|
+
const outputFile = path.join(srcDir, 'slice-build.generated.d.ts');
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
const visualDir = path.join(srcDir, 'Components', 'Visual', 'Button');
|
|
274
|
+
fs.writeFileSync(
|
|
275
|
+
path.join(visualDir, 'Button.js'),
|
|
276
|
+
`export default class Button extends HTMLElement {
|
|
277
|
+
static props = { value: { type: 'string' } };
|
|
278
|
+
}`,
|
|
279
|
+
'utf8'
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
const result = await generateTypesFile({
|
|
283
|
+
projectRoot: tmpRoot,
|
|
284
|
+
outputPath: outputFile
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
assert.equal(result.componentsProcessed, 1);
|
|
288
|
+
assert.equal(fs.existsSync(result.outputPath), true);
|
|
289
|
+
|
|
290
|
+
const declaration = fs.readFileSync(result.outputPath, 'utf8');
|
|
291
|
+
assert.match(declaration, /export interface ButtonProps/);
|
|
292
|
+
assert.match(declaration, /build<K extends SliceComponentName>/);
|
|
293
|
+
} finally {
|
|
294
|
+
await cleanupTestProject(tmpRoot);
|
|
295
|
+
}
|
|
311
296
|
});
|
|
312
297
|
|
|
313
298
|
test('ensureEditorConfigForTypes augments existing jsconfig include list', async () => {
|
|
314
|
-
const tmpRoot =
|
|
299
|
+
const tmpRoot = await createTestProject();
|
|
315
300
|
const outputFile = path.join(tmpRoot, 'src', 'slice-build.generated.d.ts');
|
|
316
301
|
const jsconfigPath = path.join(tmpRoot, 'jsconfig.json');
|
|
317
302
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
303
|
+
try {
|
|
304
|
+
fs.writeFileSync(outputFile, 'export {};\n', 'utf8');
|
|
305
|
+
fs.writeFileSync(
|
|
306
|
+
jsconfigPath,
|
|
307
|
+
JSON.stringify(
|
|
308
|
+
{
|
|
309
|
+
compilerOptions: {
|
|
310
|
+
allowJs: true
|
|
311
|
+
},
|
|
312
|
+
include: ['src/Components/**/*.js', 'src/**/*.js', 'api/**/*.js', 'tests/**/*.js']
|
|
326
313
|
},
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
314
|
+
null,
|
|
315
|
+
2
|
|
316
|
+
),
|
|
317
|
+
'utf8'
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
const result = await ensureEditorConfigForTypes({
|
|
321
|
+
projectRoot: tmpRoot,
|
|
322
|
+
outputPath: outputFile
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
assert.equal(result.mode, 'updated_jsconfig');
|
|
326
|
+
|
|
327
|
+
const jsconfig = JSON.parse(fs.readFileSync(jsconfigPath, 'utf8'));
|
|
328
|
+
assert.equal(jsconfig.include.includes('src/Components/**/*.js'), true);
|
|
329
|
+
assert.equal(jsconfig.include.includes('src/**/*.d.ts'), true);
|
|
330
|
+
assert.equal(jsconfig.include.includes('src/**/*.js'), false);
|
|
331
|
+
assert.equal(jsconfig.include.includes('api/**/*.js'), false);
|
|
332
|
+
assert.equal(jsconfig.include.includes('tests/**/*.js'), false);
|
|
333
|
+
assert.equal(jsconfig.compilerOptions.allowJs, true);
|
|
334
|
+
assert.equal(jsconfig.compilerOptions.checkJs, true);
|
|
335
|
+
assert.equal(jsconfig.compilerOptions.noImplicitAny, false);
|
|
336
|
+
assert.equal(jsconfig.compilerOptions.strictNullChecks, false);
|
|
337
|
+
assert.equal(jsconfig.compilerOptions.strict, false);
|
|
338
|
+
assert.equal(Array.isArray(jsconfig.exclude), true);
|
|
339
|
+
assert.equal(jsconfig.exclude.includes('src/libs/**'), true);
|
|
340
|
+
assert.equal(jsconfig.exclude.includes('tests/**'), true);
|
|
341
|
+
} finally {
|
|
342
|
+
await cleanupTestProject(tmpRoot);
|
|
343
|
+
}
|
|
356
344
|
});
|