@oamm/textor 1.0.13 → 1.0.14
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 +19 -0
- package/dist/bin/textor.js +171 -101
- package/dist/bin/textor.js.map +1 -1
- package/dist/index.cjs +169 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +169 -103
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -209,6 +209,25 @@ pnpm textor rename component Header SiteHeader
|
|
|
209
209
|
|
|
210
210
|
Use `--scan` to update imports across the entire project.
|
|
211
211
|
|
|
212
|
+
### add
|
|
213
|
+
Add a new sub-item (api, hook, test, etc.) to an existing feature or component. This command is additive and will not overwrite existing files unless `--force` is used.
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# Add API to an existing feature
|
|
217
|
+
pnpm textor add api auth/login
|
|
218
|
+
|
|
219
|
+
# Add hooks to an existing component
|
|
220
|
+
pnpm textor add hook Button
|
|
221
|
+
|
|
222
|
+
# Add tests and readme to a feature
|
|
223
|
+
pnpm textor add test auth/login
|
|
224
|
+
pnpm textor add readme auth/login
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Textor automatically detects if the target is a feature or a component based on its state.
|
|
228
|
+
|
|
229
|
+
You can also use the original `add-section` or `create-component` commands with the same flags to add items; they now also support additive mode.
|
|
230
|
+
|
|
212
231
|
### remove-section / remove-component
|
|
213
232
|
Safely remove Textor-managed modules.
|
|
214
233
|
|
package/dist/bin/textor.js
CHANGED
|
@@ -716,17 +716,6 @@ async function safeDelete(filePath, options = {}) {
|
|
|
716
716
|
return { deleted: true };
|
|
717
717
|
}
|
|
718
718
|
|
|
719
|
-
async function ensureNotExists(filePath, force = false) {
|
|
720
|
-
if (existsSync(filePath)) {
|
|
721
|
-
if (!force) {
|
|
722
|
-
throw new Error(
|
|
723
|
-
`File already exists: ${filePath}\n` +
|
|
724
|
-
`Use --force to overwrite.`
|
|
725
|
-
);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
|
|
730
719
|
async function ensureDir(dirPath) {
|
|
731
720
|
await mkdir(dirPath, { recursive: true });
|
|
732
721
|
}
|
|
@@ -2082,19 +2071,25 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2082
2071
|
}
|
|
2083
2072
|
}
|
|
2084
2073
|
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
if
|
|
2091
|
-
if (
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2074
|
+
const featureExists = existsSync(featureFilePath);
|
|
2075
|
+
if (featureExists && !options.force) {
|
|
2076
|
+
console.log(`ℹ Feature already exists at ${featureFilePath}. Entering additive mode.`);
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
// Check sub-items only if not in force mode
|
|
2080
|
+
if (!options.force) {
|
|
2081
|
+
if (shouldCreateIndex && existsSync(indexFilePath)) console.log(` - Skipping existing index: ${indexFilePath}`);
|
|
2082
|
+
if (shouldCreateContext && existsSync(contextFilePath)) console.log(` - Skipping existing context: ${contextFilePath}`);
|
|
2083
|
+
if (shouldCreateHooks && existsSync(hookFilePath)) console.log(` - Skipping existing hook: ${hookFilePath}`);
|
|
2084
|
+
if (shouldCreateTests && existsSync(testFilePath)) console.log(` - Skipping existing test: ${testFilePath}`);
|
|
2085
|
+
if (shouldCreateTypes && existsSync(typesFilePath)) console.log(` - Skipping existing types: ${typesFilePath}`);
|
|
2086
|
+
if (shouldCreateApi && existsSync(apiFilePath)) console.log(` - Skipping existing api: ${apiFilePath}`);
|
|
2087
|
+
if (shouldCreateServices && existsSync(servicesFilePath)) console.log(` - Skipping existing services: ${servicesFilePath}`);
|
|
2088
|
+
if (shouldCreateSchemas && existsSync(schemasFilePath)) console.log(` - Skipping existing schemas: ${schemasFilePath}`);
|
|
2089
|
+
if (shouldCreateReadme && existsSync(readmeFilePath)) console.log(` - Skipping existing readme: ${readmeFilePath}`);
|
|
2090
|
+
if (shouldCreateStories && existsSync(storiesFilePath)) console.log(` - Skipping existing stories: ${storiesFilePath}`);
|
|
2091
|
+
if (shouldCreateScriptsDir && existsSync(scriptsIndexPath)) console.log(` - Skipping existing scripts: ${scriptsIndexPath}`);
|
|
2092
|
+
}
|
|
2098
2093
|
|
|
2099
2094
|
let layoutImportPath = null;
|
|
2100
2095
|
const cliProps = options.prop || {};
|
|
@@ -2235,21 +2230,23 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2235
2230
|
|
|
2236
2231
|
const featureSignature = getSignature(config, config.naming.featureExtension === '.astro' ? 'astro' : 'tsx');
|
|
2237
2232
|
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2233
|
+
if (!featureExists || options.force) {
|
|
2234
|
+
const featureHash = await writeFileWithSignature(
|
|
2235
|
+
featureFilePath,
|
|
2236
|
+
featureContent,
|
|
2237
|
+
featureSignature,
|
|
2238
|
+
config.hashing?.normalization
|
|
2239
|
+
);
|
|
2240
|
+
await registerFile(featureFilePath, {
|
|
2241
|
+
kind: 'feature',
|
|
2242
|
+
template: 'feature',
|
|
2243
|
+
hash: featureHash,
|
|
2244
|
+
owner: normalizedRoute
|
|
2245
|
+
});
|
|
2246
|
+
writtenFiles.push(featureFilePath);
|
|
2247
|
+
}
|
|
2251
2248
|
|
|
2252
|
-
if (shouldCreateScriptsDir) {
|
|
2249
|
+
if (shouldCreateScriptsDir && (!existsSync(scriptsIndexPath) || options.force)) {
|
|
2253
2250
|
const hash = await writeFileWithSignature(
|
|
2254
2251
|
scriptsIndexPath,
|
|
2255
2252
|
generateScriptsIndexTemplate(),
|
|
@@ -2265,7 +2262,7 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2265
2262
|
writtenFiles.push(scriptsIndexPath);
|
|
2266
2263
|
}
|
|
2267
2264
|
|
|
2268
|
-
if (shouldCreateIndex) {
|
|
2265
|
+
if (shouldCreateIndex && (!existsSync(indexFilePath) || options.force)) {
|
|
2269
2266
|
const indexContent = generateIndexTemplate(featureComponentName, config.naming.featureExtension);
|
|
2270
2267
|
const hash = await writeFileWithSignature(
|
|
2271
2268
|
indexFilePath,
|
|
@@ -2282,7 +2279,7 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2282
2279
|
writtenFiles.push(indexFilePath);
|
|
2283
2280
|
}
|
|
2284
2281
|
|
|
2285
|
-
if (shouldCreateApi) {
|
|
2282
|
+
if (shouldCreateApi && (!existsSync(apiFilePath) || options.force)) {
|
|
2286
2283
|
const apiContent = generateApiTemplate(featureComponentName);
|
|
2287
2284
|
const hash = await writeFileWithSignature(
|
|
2288
2285
|
apiFilePath,
|
|
@@ -2299,7 +2296,7 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2299
2296
|
writtenFiles.push(apiFilePath);
|
|
2300
2297
|
}
|
|
2301
2298
|
|
|
2302
|
-
if (shouldCreateServices) {
|
|
2299
|
+
if (shouldCreateServices && (!existsSync(servicesFilePath) || options.force)) {
|
|
2303
2300
|
const servicesContent = generateServiceTemplate(featureComponentName);
|
|
2304
2301
|
const hash = await writeFileWithSignature(
|
|
2305
2302
|
servicesFilePath,
|
|
@@ -2316,7 +2313,7 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2316
2313
|
writtenFiles.push(servicesFilePath);
|
|
2317
2314
|
}
|
|
2318
2315
|
|
|
2319
|
-
if (shouldCreateSchemas) {
|
|
2316
|
+
if (shouldCreateSchemas && (!existsSync(schemasFilePath) || options.force)) {
|
|
2320
2317
|
const schemasContent = generateSchemaTemplate(featureComponentName);
|
|
2321
2318
|
const hash = await writeFileWithSignature(
|
|
2322
2319
|
schemasFilePath,
|
|
@@ -2333,7 +2330,7 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2333
2330
|
writtenFiles.push(schemasFilePath);
|
|
2334
2331
|
}
|
|
2335
2332
|
|
|
2336
|
-
if (shouldCreateHooks) {
|
|
2333
|
+
if (shouldCreateHooks && (!existsSync(hookFilePath) || options.force)) {
|
|
2337
2334
|
const hookName = getHookFunctionName(featureComponentName);
|
|
2338
2335
|
const hookContent = generateHookTemplate(featureComponentName, hookName);
|
|
2339
2336
|
const hash = await writeFileWithSignature(
|
|
@@ -2351,7 +2348,7 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2351
2348
|
writtenFiles.push(hookFilePath);
|
|
2352
2349
|
}
|
|
2353
2350
|
|
|
2354
|
-
if (shouldCreateContext) {
|
|
2351
|
+
if (shouldCreateContext && (!existsSync(contextFilePath) || options.force)) {
|
|
2355
2352
|
const contextContent = generateContextTemplate(featureComponentName);
|
|
2356
2353
|
const hash = await writeFileWithSignature(
|
|
2357
2354
|
contextFilePath,
|
|
@@ -2368,7 +2365,7 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2368
2365
|
writtenFiles.push(contextFilePath);
|
|
2369
2366
|
}
|
|
2370
2367
|
|
|
2371
|
-
if (shouldCreateTests) {
|
|
2368
|
+
if (shouldCreateTests && (!existsSync(testFilePath) || options.force)) {
|
|
2372
2369
|
const relativeFeaturePath = `./${path.basename(featureFilePath)}`;
|
|
2373
2370
|
const testContent = generateTestTemplate(featureComponentName, relativeFeaturePath);
|
|
2374
2371
|
const hash = await writeFileWithSignature(
|
|
@@ -2386,7 +2383,7 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2386
2383
|
writtenFiles.push(testFilePath);
|
|
2387
2384
|
}
|
|
2388
2385
|
|
|
2389
|
-
if (shouldCreateTypes) {
|
|
2386
|
+
if (shouldCreateTypes && (!existsSync(typesFilePath) || options.force)) {
|
|
2390
2387
|
const typesContent = generateTypesTemplate(featureComponentName);
|
|
2391
2388
|
const hash = await writeFileWithSignature(
|
|
2392
2389
|
typesFilePath,
|
|
@@ -2403,7 +2400,7 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2403
2400
|
writtenFiles.push(typesFilePath);
|
|
2404
2401
|
}
|
|
2405
2402
|
|
|
2406
|
-
if (shouldCreateReadme) {
|
|
2403
|
+
if (shouldCreateReadme && (!existsSync(readmeFilePath) || options.force)) {
|
|
2407
2404
|
const readmeContent = generateReadmeTemplate(featureComponentName);
|
|
2408
2405
|
const hash = await writeFileWithSignature(
|
|
2409
2406
|
readmeFilePath,
|
|
@@ -2420,7 +2417,7 @@ async function addSectionCommand(route, featurePath, options) {
|
|
|
2420
2417
|
writtenFiles.push(readmeFilePath);
|
|
2421
2418
|
}
|
|
2422
2419
|
|
|
2423
|
-
if (shouldCreateStories) {
|
|
2420
|
+
if (shouldCreateStories && (!existsSync(storiesFilePath) || options.force)) {
|
|
2424
2421
|
const relativePath = `./${path.basename(featureFilePath)}`;
|
|
2425
2422
|
const storiesContent = generateStoriesTemplate(featureComponentName, relativePath);
|
|
2426
2423
|
const hash = await writeFileWithSignature(
|
|
@@ -3437,20 +3434,26 @@ async function createComponentCommand(componentName, options) {
|
|
|
3437
3434
|
return;
|
|
3438
3435
|
}
|
|
3439
3436
|
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
if
|
|
3446
|
-
if (
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3437
|
+
const componentExists = existsSync(componentFilePath);
|
|
3438
|
+
if (componentExists && !options.force) {
|
|
3439
|
+
console.log(`ℹ Component already exists at ${componentFilePath}. Entering additive mode.`);
|
|
3440
|
+
}
|
|
3441
|
+
|
|
3442
|
+
// Check sub-items only if not in force mode
|
|
3443
|
+
if (!options.force) {
|
|
3444
|
+
if (existsSync(indexFilePath)) console.log(` - Skipping existing index: ${indexFilePath}`);
|
|
3445
|
+
if (shouldCreateContext && existsSync(contextFilePath)) console.log(` - Skipping existing context: ${contextFilePath}`);
|
|
3446
|
+
if (shouldCreateHook && existsSync(hookFilePath)) console.log(` - Skipping existing hook: ${hookFilePath}`);
|
|
3447
|
+
if (shouldCreateTests && existsSync(testFilePath)) console.log(` - Skipping existing test: ${testFilePath}`);
|
|
3448
|
+
if (shouldCreateConfig && existsSync(configFilePath)) console.log(` - Skipping existing config: ${configFilePath}`);
|
|
3449
|
+
if (shouldCreateConstants && existsSync(constantsFilePath)) console.log(` - Skipping existing constants: ${constantsFilePath}`);
|
|
3450
|
+
if (shouldCreateTypes && existsSync(typesFilePath)) console.log(` - Skipping existing types: ${typesFilePath}`);
|
|
3451
|
+
if (shouldCreateApi && existsSync(apiFilePath)) console.log(` - Skipping existing api: ${apiFilePath}`);
|
|
3452
|
+
if (shouldCreateServices && existsSync(servicesFilePath)) console.log(` - Skipping existing services: ${servicesFilePath}`);
|
|
3453
|
+
if (shouldCreateSchemas && existsSync(schemasFilePath)) console.log(` - Skipping existing schemas: ${schemasFilePath}`);
|
|
3454
|
+
if (shouldCreateReadme && existsSync(readmeFilePath)) console.log(` - Skipping existing readme: ${readmeFilePath}`);
|
|
3455
|
+
if (shouldCreateStories && existsSync(storiesFilePath)) console.log(` - Skipping existing stories: ${storiesFilePath}`);
|
|
3456
|
+
}
|
|
3454
3457
|
|
|
3455
3458
|
await ensureDir(componentDir);
|
|
3456
3459
|
|
|
@@ -3468,37 +3471,42 @@ async function createComponentCommand(componentName, options) {
|
|
|
3468
3471
|
const componentContent = generateComponentTemplate(normalizedName, framework, config.naming.componentExtension);
|
|
3469
3472
|
const signature = getSignature(config, config.naming.componentExtension === '.astro' ? 'astro' : 'tsx');
|
|
3470
3473
|
|
|
3471
|
-
const
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3474
|
+
const writtenFiles = [];
|
|
3475
|
+
|
|
3476
|
+
if (!componentExists || options.force) {
|
|
3477
|
+
const componentHash = await writeFileWithSignature(
|
|
3478
|
+
componentFilePath,
|
|
3479
|
+
componentContent,
|
|
3480
|
+
signature,
|
|
3481
|
+
config.hashing?.normalization
|
|
3482
|
+
);
|
|
3483
|
+
await registerFile(componentFilePath, {
|
|
3484
|
+
kind: 'component',
|
|
3485
|
+
template: 'component',
|
|
3486
|
+
hash: componentHash,
|
|
3487
|
+
owner: normalizedName
|
|
3488
|
+
});
|
|
3489
|
+
writtenFiles.push(componentFilePath);
|
|
3490
|
+
}
|
|
3483
3491
|
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3492
|
+
if (!existsSync(indexFilePath) || options.force) {
|
|
3493
|
+
const indexContent = generateIndexTemplate(normalizedName, config.naming.componentExtension);
|
|
3494
|
+
const indexHash = await writeFileWithSignature(
|
|
3495
|
+
indexFilePath,
|
|
3496
|
+
indexContent,
|
|
3497
|
+
getSignature(config, 'typescript'),
|
|
3498
|
+
config.hashing?.normalization
|
|
3499
|
+
);
|
|
3500
|
+
await registerFile(indexFilePath, {
|
|
3501
|
+
kind: 'component-file',
|
|
3502
|
+
template: 'index',
|
|
3503
|
+
hash: indexHash,
|
|
3504
|
+
owner: normalizedName
|
|
3505
|
+
});
|
|
3506
|
+
writtenFiles.push(indexFilePath);
|
|
3507
|
+
}
|
|
3500
3508
|
|
|
3501
|
-
if (shouldCreateTypes) {
|
|
3509
|
+
if (shouldCreateTypes && (!existsSync(typesFilePath) || options.force)) {
|
|
3502
3510
|
const typesContent = generateTypesTemplate(normalizedName);
|
|
3503
3511
|
const hash = await writeFileWithSignature(
|
|
3504
3512
|
typesFilePath,
|
|
@@ -3515,7 +3523,7 @@ async function createComponentCommand(componentName, options) {
|
|
|
3515
3523
|
writtenFiles.push(typesFilePath);
|
|
3516
3524
|
}
|
|
3517
3525
|
|
|
3518
|
-
if (shouldCreateContext) {
|
|
3526
|
+
if (shouldCreateContext && (!existsSync(contextFilePath) || options.force)) {
|
|
3519
3527
|
const contextContent = generateContextTemplate(normalizedName);
|
|
3520
3528
|
const hash = await writeFileWithSignature(
|
|
3521
3529
|
contextFilePath,
|
|
@@ -3532,7 +3540,7 @@ async function createComponentCommand(componentName, options) {
|
|
|
3532
3540
|
writtenFiles.push(contextFilePath);
|
|
3533
3541
|
}
|
|
3534
3542
|
|
|
3535
|
-
if (shouldCreateHook) {
|
|
3543
|
+
if (shouldCreateHook && (!existsSync(hookFilePath) || options.force)) {
|
|
3536
3544
|
const hookName = getHookFunctionName(normalizedName);
|
|
3537
3545
|
const hookContent = generateHookTemplate(normalizedName, hookName);
|
|
3538
3546
|
const hash = await writeFileWithSignature(
|
|
@@ -3550,7 +3558,7 @@ async function createComponentCommand(componentName, options) {
|
|
|
3550
3558
|
writtenFiles.push(hookFilePath);
|
|
3551
3559
|
}
|
|
3552
3560
|
|
|
3553
|
-
if (shouldCreateTests) {
|
|
3561
|
+
if (shouldCreateTests && (!existsSync(testFilePath) || options.force)) {
|
|
3554
3562
|
const relativeComponentPath = `../${normalizedName}${config.naming.componentExtension}`;
|
|
3555
3563
|
const testContent = generateTestTemplate(normalizedName, relativeComponentPath);
|
|
3556
3564
|
const hash = await writeFileWithSignature(
|
|
@@ -3568,7 +3576,7 @@ async function createComponentCommand(componentName, options) {
|
|
|
3568
3576
|
writtenFiles.push(testFilePath);
|
|
3569
3577
|
}
|
|
3570
3578
|
|
|
3571
|
-
if (shouldCreateConfig) {
|
|
3579
|
+
if (shouldCreateConfig && (!existsSync(configFilePath) || options.force)) {
|
|
3572
3580
|
const configContent = generateConfigTemplate(normalizedName);
|
|
3573
3581
|
const hash = await writeFileWithSignature(
|
|
3574
3582
|
configFilePath,
|
|
@@ -3585,7 +3593,7 @@ async function createComponentCommand(componentName, options) {
|
|
|
3585
3593
|
writtenFiles.push(configFilePath);
|
|
3586
3594
|
}
|
|
3587
3595
|
|
|
3588
|
-
if (shouldCreateConstants) {
|
|
3596
|
+
if (shouldCreateConstants && (!existsSync(constantsFilePath) || options.force)) {
|
|
3589
3597
|
const constantsContent = generateConstantsTemplate(normalizedName);
|
|
3590
3598
|
const hash = await writeFileWithSignature(
|
|
3591
3599
|
constantsFilePath,
|
|
@@ -3602,7 +3610,7 @@ async function createComponentCommand(componentName, options) {
|
|
|
3602
3610
|
writtenFiles.push(constantsFilePath);
|
|
3603
3611
|
}
|
|
3604
3612
|
|
|
3605
|
-
if (shouldCreateApi) {
|
|
3613
|
+
if (shouldCreateApi && (!existsSync(apiFilePath) || options.force)) {
|
|
3606
3614
|
const apiContent = generateApiTemplate(normalizedName);
|
|
3607
3615
|
const hash = await writeFileWithSignature(
|
|
3608
3616
|
apiFilePath,
|
|
@@ -3619,7 +3627,7 @@ async function createComponentCommand(componentName, options) {
|
|
|
3619
3627
|
writtenFiles.push(apiFilePath);
|
|
3620
3628
|
}
|
|
3621
3629
|
|
|
3622
|
-
if (shouldCreateServices) {
|
|
3630
|
+
if (shouldCreateServices && (!existsSync(servicesFilePath) || options.force)) {
|
|
3623
3631
|
const servicesContent = generateServiceTemplate(normalizedName);
|
|
3624
3632
|
const hash = await writeFileWithSignature(
|
|
3625
3633
|
servicesFilePath,
|
|
@@ -3636,7 +3644,7 @@ async function createComponentCommand(componentName, options) {
|
|
|
3636
3644
|
writtenFiles.push(servicesFilePath);
|
|
3637
3645
|
}
|
|
3638
3646
|
|
|
3639
|
-
if (shouldCreateSchemas) {
|
|
3647
|
+
if (shouldCreateSchemas && (!existsSync(schemasFilePath) || options.force)) {
|
|
3640
3648
|
const schemasContent = generateSchemaTemplate(normalizedName);
|
|
3641
3649
|
const hash = await writeFileWithSignature(
|
|
3642
3650
|
schemasFilePath,
|
|
@@ -3653,7 +3661,7 @@ async function createComponentCommand(componentName, options) {
|
|
|
3653
3661
|
writtenFiles.push(schemasFilePath);
|
|
3654
3662
|
}
|
|
3655
3663
|
|
|
3656
|
-
if (shouldCreateReadme) {
|
|
3664
|
+
if (shouldCreateReadme && (!existsSync(readmeFilePath) || options.force)) {
|
|
3657
3665
|
const readmeContent = generateReadmeTemplate(normalizedName);
|
|
3658
3666
|
const hash = await writeFileWithSignature(
|
|
3659
3667
|
readmeFilePath,
|
|
@@ -3670,7 +3678,7 @@ async function createComponentCommand(componentName, options) {
|
|
|
3670
3678
|
writtenFiles.push(readmeFilePath);
|
|
3671
3679
|
}
|
|
3672
3680
|
|
|
3673
|
-
if (shouldCreateStories) {
|
|
3681
|
+
if (shouldCreateStories && (!existsSync(storiesFilePath) || options.force)) {
|
|
3674
3682
|
const relativePath = `./${normalizedName}${config.naming.componentExtension}`;
|
|
3675
3683
|
const storiesContent = generateStoriesTemplate(normalizedName, relativePath);
|
|
3676
3684
|
const hash = await writeFileWithSignature(
|
|
@@ -4601,6 +4609,61 @@ async function pruneMissingCommand(options = {}) {
|
|
|
4601
4609
|
}
|
|
4602
4610
|
}
|
|
4603
4611
|
|
|
4612
|
+
/**
|
|
4613
|
+
* Add a new item (hook, api, service, etc.) to an existing feature or component.
|
|
4614
|
+
*
|
|
4615
|
+
* @param {string} itemType The type of item to add (e.g., 'api', 'hook', 'service')
|
|
4616
|
+
* @param {string} targetName The name of the feature or component
|
|
4617
|
+
* @param {Object} options Additional options from Commander
|
|
4618
|
+
*/
|
|
4619
|
+
async function addItemCommand(itemType, targetName, options) {
|
|
4620
|
+
try {
|
|
4621
|
+
const state = await loadState();
|
|
4622
|
+
|
|
4623
|
+
// Normalize itemType
|
|
4624
|
+
let normalizedItem = itemType.toLowerCase();
|
|
4625
|
+
if (normalizedItem === 'test') normalizedItem = 'tests';
|
|
4626
|
+
if (normalizedItem === 'service') normalizedItem = 'services';
|
|
4627
|
+
if (normalizedItem === 'schema') normalizedItem = 'schemas';
|
|
4628
|
+
if (normalizedItem === 'hook') normalizedItem = 'hooks'; // for add-section
|
|
4629
|
+
|
|
4630
|
+
// Try to find as section (feature) first
|
|
4631
|
+
let section = findSection(state, targetName);
|
|
4632
|
+
let component = findComponent(state, targetName);
|
|
4633
|
+
|
|
4634
|
+
// If not found by exact name, try to find by featurePath or part of it
|
|
4635
|
+
if (!section && !component) {
|
|
4636
|
+
section = state.sections.find(s => s.featurePath === targetName || s.featurePath.endsWith('/' + targetName));
|
|
4637
|
+
}
|
|
4638
|
+
|
|
4639
|
+
if (!section && !component) {
|
|
4640
|
+
throw new Error(`Target not found in state: "${targetName}". Please use "add-section" or "create-component" directly if it's not managed by Textor.`);
|
|
4641
|
+
}
|
|
4642
|
+
|
|
4643
|
+
const flags = { [normalizedItem]: true };
|
|
4644
|
+
// Also set singular for create-component which uses 'hook'
|
|
4645
|
+
if (normalizedItem === 'hooks') flags.hook = true;
|
|
4646
|
+
|
|
4647
|
+
if (section) {
|
|
4648
|
+
console.log(`ℹ Adding ${normalizedItem} to feature: ${section.featurePath}`);
|
|
4649
|
+
return await addSectionCommand(undefined, section.featurePath, { ...options, ...flags });
|
|
4650
|
+
}
|
|
4651
|
+
|
|
4652
|
+
if (component) {
|
|
4653
|
+
console.log(`ℹ Adding ${normalizedItem} to component: ${component.name}`);
|
|
4654
|
+
// For create-component, we might need to be careful with flags that are on by default
|
|
4655
|
+
// but getEffectiveOptions should handle it if we pass them explicitly as true.
|
|
4656
|
+
return await createComponentCommand(component.name, { ...options, ...flags });
|
|
4657
|
+
}
|
|
4658
|
+
} catch (error) {
|
|
4659
|
+
console.error('Error:', error.message);
|
|
4660
|
+
if (typeof process.exit === 'function' && process.env.NODE_ENV !== 'test') {
|
|
4661
|
+
process.exit(1);
|
|
4662
|
+
}
|
|
4663
|
+
throw error;
|
|
4664
|
+
}
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4604
4667
|
/**
|
|
4605
4668
|
* Dispatcher for rename commands.
|
|
4606
4669
|
*/
|
|
@@ -4860,5 +4923,12 @@ program
|
|
|
4860
4923
|
.option('--dry-run', 'Show what would be renamed without applying')
|
|
4861
4924
|
.action(renameCommand);
|
|
4862
4925
|
|
|
4926
|
+
program
|
|
4927
|
+
.command('add <item> <target>')
|
|
4928
|
+
.description('Add a sub-item (api, hook, test, etc.) to an existing feature or component')
|
|
4929
|
+
.option('--force', 'Overwrite existing files')
|
|
4930
|
+
.option('--dry-run', 'Show what would be created without creating')
|
|
4931
|
+
.action(addItemCommand);
|
|
4932
|
+
|
|
4863
4933
|
program.parse();
|
|
4864
4934
|
//# sourceMappingURL=textor.js.map
|
package/dist/bin/textor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"textor.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"textor.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|