@oamm/textor 1.0.13 → 1.0.16

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/dist/index.d.ts CHANGED
@@ -31,7 +31,7 @@ declare function statusCommand(): Promise<void>;
31
31
 
32
32
  declare function syncCommand(options: any): Promise<void>;
33
33
 
34
- declare function adoptCommand(identifier: any, options: any): Promise<void>;
34
+ declare function adoptCommand(kind: any, arg2: any, arg3: any, options: any): Promise<void>;
35
35
 
36
36
  declare function upgradeConfigCommand(options: any): Promise<void>;
37
37
 
@@ -53,4 +53,13 @@ declare function pruneMissingCommand(options?: {
53
53
  */
54
54
  declare function renameCommand(type: any, oldName: any, newName: any, options: any): Promise<void>;
55
55
 
56
- export { addSectionCommand, adoptCommand, createComponentCommand, initCommand, listSectionsCommand, moveSectionCommand, normalizeStateCommand, pruneMissingCommand, removeComponentCommand, removeSectionCommand, renameCommand, statusCommand, syncCommand, upgradeConfigCommand, validateStateCommand };
56
+ /**
57
+ * Add a new item (hook, api, service, etc.) to an existing feature or component.
58
+ *
59
+ * @param {string} itemType The type of item to add (e.g., 'api', 'hook', 'service')
60
+ * @param {string} targetName The name of the feature or component
61
+ * @param {Object} options Additional options from Commander
62
+ */
63
+ declare function addItemCommand(itemType: string, targetName: string, options: any): Promise<void>;
64
+
65
+ export { addItemCommand, addSectionCommand, adoptCommand, createComponentCommand, initCommand, listSectionsCommand, moveSectionCommand, normalizeStateCommand, pruneMissingCommand, removeComponentCommand, removeSectionCommand, renameCommand, statusCommand, syncCommand, upgradeConfigCommand, validateStateCommand };
package/dist/index.js CHANGED
@@ -635,14 +635,6 @@ async function safeDelete(filePath, options = {}) {
635
635
  await unlink(filePath);
636
636
  return { deleted: true };
637
637
  }
638
- async function ensureNotExists(filePath, force = false) {
639
- if (existsSync(filePath)) {
640
- if (!force) {
641
- throw new Error(`File already exists: ${filePath}\n` +
642
- `Use --force to overwrite.`);
643
- }
644
- }
645
- }
646
638
  async function ensureDir(dirPath) {
647
639
  await mkdir(dirPath, { recursive: true });
648
640
  }
@@ -1542,18 +1534,26 @@ function reconstructSections(state, config) {
1542
1534
  // Keep existing sections if their files still exist
1543
1535
  const validSections = (state.sections || []).filter(section => {
1544
1536
  // Check if route file exists in state.files
1545
- const routeFile = Object.keys(files).find(f => {
1537
+ const routeFile = section.route ? Object.keys(files).find(f => {
1546
1538
  const normalizedF = f.replace(/\\/g, '/');
1547
1539
  const routePath = section.route === '/' ? 'index' : section.route.slice(1);
1548
1540
  return normalizedF.startsWith(pagesRoot + '/' + routePath + '.') ||
1549
1541
  normalizedF === pagesRoot + '/' + routePath + '/index.astro'; // nested mode
1550
- });
1542
+ }) : true;
1551
1543
  // Check if feature directory has at least one file in state.files
1552
- const hasFeatureFiles = Object.keys(files).some(f => f.replace(/\\/g, '/').startsWith(section.featurePath.replace(/\\/g, '/') + '/'));
1544
+ const hasFeatureFiles = section.featurePath ? Object.keys(files).some(f => {
1545
+ const normalizedF = f.replace(/\\/g, '/');
1546
+ const featPath = section.featurePath.replace(/\\/g, '/');
1547
+ return normalizedF.startsWith(featPath + '/') ||
1548
+ normalizedF.startsWith(featuresRoot + '/' + featPath + '/');
1549
+ }) : false;
1553
1550
  return routeFile && hasFeatureFiles;
1554
1551
  });
1555
1552
  const sections = new Map();
1556
- validSections.forEach(s => sections.set(s.route, s));
1553
+ validSections.forEach(s => {
1554
+ const key = s.route || `feature:${s.featurePath}`;
1555
+ sections.set(key, s);
1556
+ });
1557
1557
  // Try to discover new sections
1558
1558
  for (const filePath in files) {
1559
1559
  const normalizedPath = filePath.replace(/\\/g, '/');
@@ -1794,29 +1794,35 @@ async function addSectionCommand(route, featurePath, options) {
1794
1794
  }
1795
1795
  }
1796
1796
  }
1797
- await ensureNotExists(featureFilePath, options.force);
1798
- if (shouldCreateIndex)
1799
- await ensureNotExists(indexFilePath, options.force);
1800
- if (shouldCreateContext)
1801
- await ensureNotExists(contextFilePath, options.force);
1802
- if (shouldCreateHooks)
1803
- await ensureNotExists(hookFilePath, options.force);
1804
- if (shouldCreateTests)
1805
- await ensureNotExists(testFilePath, options.force);
1806
- if (shouldCreateTypes)
1807
- await ensureNotExists(typesFilePath, options.force);
1808
- if (shouldCreateApi)
1809
- await ensureNotExists(apiFilePath, options.force);
1810
- if (shouldCreateServices)
1811
- await ensureNotExists(servicesFilePath, options.force);
1812
- if (shouldCreateSchemas)
1813
- await ensureNotExists(schemasFilePath, options.force);
1814
- if (shouldCreateReadme)
1815
- await ensureNotExists(readmeFilePath, options.force);
1816
- if (shouldCreateStories)
1817
- await ensureNotExists(storiesFilePath, options.force);
1818
- if (shouldCreateScriptsDir)
1819
- await ensureNotExists(scriptsIndexPath, options.force);
1797
+ const featureExists = existsSync(featureFilePath);
1798
+ if (featureExists && !options.force) {
1799
+ console.log(`ℹ Feature already exists at ${featureFilePath}. Entering additive mode.`);
1800
+ }
1801
+ // Check sub-items only if not in force mode
1802
+ if (!options.force) {
1803
+ if (shouldCreateIndex && existsSync(indexFilePath))
1804
+ console.log(` - Skipping existing index: ${indexFilePath}`);
1805
+ if (shouldCreateContext && existsSync(contextFilePath))
1806
+ console.log(` - Skipping existing context: ${contextFilePath}`);
1807
+ if (shouldCreateHooks && existsSync(hookFilePath))
1808
+ console.log(` - Skipping existing hook: ${hookFilePath}`);
1809
+ if (shouldCreateTests && existsSync(testFilePath))
1810
+ console.log(` - Skipping existing test: ${testFilePath}`);
1811
+ if (shouldCreateTypes && existsSync(typesFilePath))
1812
+ console.log(` - Skipping existing types: ${typesFilePath}`);
1813
+ if (shouldCreateApi && existsSync(apiFilePath))
1814
+ console.log(` - Skipping existing api: ${apiFilePath}`);
1815
+ if (shouldCreateServices && existsSync(servicesFilePath))
1816
+ console.log(` - Skipping existing services: ${servicesFilePath}`);
1817
+ if (shouldCreateSchemas && existsSync(schemasFilePath))
1818
+ console.log(` - Skipping existing schemas: ${schemasFilePath}`);
1819
+ if (shouldCreateReadme && existsSync(readmeFilePath))
1820
+ console.log(` - Skipping existing readme: ${readmeFilePath}`);
1821
+ if (shouldCreateStories && existsSync(storiesFilePath))
1822
+ console.log(` - Skipping existing stories: ${storiesFilePath}`);
1823
+ if (shouldCreateScriptsDir && existsSync(scriptsIndexPath))
1824
+ console.log(` - Skipping existing scripts: ${scriptsIndexPath}`);
1825
+ }
1820
1826
  let layoutImportPath = null;
1821
1827
  const cliProps = options.prop || {};
1822
1828
  const rawLayoutProps = { ...configLayoutProps, ...cliProps };
@@ -1938,15 +1944,17 @@ async function addSectionCommand(route, featurePath, options) {
1938
1944
  if (shouldCreateTypes)
1939
1945
  await ensureDir(typesDirInside);
1940
1946
  const featureSignature = getSignature(config, config.naming.featureExtension === '.astro' ? 'astro' : 'tsx');
1941
- const featureHash = await writeFileWithSignature(featureFilePath, featureContent, featureSignature, config.hashing?.normalization);
1942
- await registerFile(featureFilePath, {
1943
- kind: 'feature',
1944
- template: 'feature',
1945
- hash: featureHash,
1946
- owner: normalizedRoute
1947
- });
1948
- writtenFiles.push(featureFilePath);
1949
- if (shouldCreateScriptsDir) {
1947
+ if (!featureExists || options.force) {
1948
+ const featureHash = await writeFileWithSignature(featureFilePath, featureContent, featureSignature, config.hashing?.normalization);
1949
+ await registerFile(featureFilePath, {
1950
+ kind: 'feature',
1951
+ template: 'feature',
1952
+ hash: featureHash,
1953
+ owner: normalizedRoute
1954
+ });
1955
+ writtenFiles.push(featureFilePath);
1956
+ }
1957
+ if (shouldCreateScriptsDir && (!existsSync(scriptsIndexPath) || options.force)) {
1950
1958
  const hash = await writeFileWithSignature(scriptsIndexPath, generateScriptsIndexTemplate(), getSignature(config, 'typescript'), config.hashing?.normalization);
1951
1959
  await registerFile(scriptsIndexPath, {
1952
1960
  kind: 'feature-file',
@@ -1956,7 +1964,7 @@ async function addSectionCommand(route, featurePath, options) {
1956
1964
  });
1957
1965
  writtenFiles.push(scriptsIndexPath);
1958
1966
  }
1959
- if (shouldCreateIndex) {
1967
+ if (shouldCreateIndex && (!existsSync(indexFilePath) || options.force)) {
1960
1968
  const indexContent = generateIndexTemplate(featureComponentName, config.naming.featureExtension);
1961
1969
  const hash = await writeFileWithSignature(indexFilePath, indexContent, getSignature(config, 'typescript'), config.hashing?.normalization);
1962
1970
  await registerFile(indexFilePath, {
@@ -1967,7 +1975,7 @@ async function addSectionCommand(route, featurePath, options) {
1967
1975
  });
1968
1976
  writtenFiles.push(indexFilePath);
1969
1977
  }
1970
- if (shouldCreateApi) {
1978
+ if (shouldCreateApi && (!existsSync(apiFilePath) || options.force)) {
1971
1979
  const apiContent = generateApiTemplate(featureComponentName);
1972
1980
  const hash = await writeFileWithSignature(apiFilePath, apiContent, getSignature(config, 'typescript'), config.hashing?.normalization);
1973
1981
  await registerFile(apiFilePath, {
@@ -1978,7 +1986,7 @@ async function addSectionCommand(route, featurePath, options) {
1978
1986
  });
1979
1987
  writtenFiles.push(apiFilePath);
1980
1988
  }
1981
- if (shouldCreateServices) {
1989
+ if (shouldCreateServices && (!existsSync(servicesFilePath) || options.force)) {
1982
1990
  const servicesContent = generateServiceTemplate(featureComponentName);
1983
1991
  const hash = await writeFileWithSignature(servicesFilePath, servicesContent, getSignature(config, 'typescript'), config.hashing?.normalization);
1984
1992
  await registerFile(servicesFilePath, {
@@ -1989,7 +1997,7 @@ async function addSectionCommand(route, featurePath, options) {
1989
1997
  });
1990
1998
  writtenFiles.push(servicesFilePath);
1991
1999
  }
1992
- if (shouldCreateSchemas) {
2000
+ if (shouldCreateSchemas && (!existsSync(schemasFilePath) || options.force)) {
1993
2001
  const schemasContent = generateSchemaTemplate(featureComponentName);
1994
2002
  const hash = await writeFileWithSignature(schemasFilePath, schemasContent, getSignature(config, 'typescript'), config.hashing?.normalization);
1995
2003
  await registerFile(schemasFilePath, {
@@ -2000,7 +2008,7 @@ async function addSectionCommand(route, featurePath, options) {
2000
2008
  });
2001
2009
  writtenFiles.push(schemasFilePath);
2002
2010
  }
2003
- if (shouldCreateHooks) {
2011
+ if (shouldCreateHooks && (!existsSync(hookFilePath) || options.force)) {
2004
2012
  const hookName = getHookFunctionName(featureComponentName);
2005
2013
  const hookContent = generateHookTemplate(featureComponentName, hookName);
2006
2014
  const hash = await writeFileWithSignature(hookFilePath, hookContent, getSignature(config, 'typescript'), config.hashing?.normalization);
@@ -2012,7 +2020,7 @@ async function addSectionCommand(route, featurePath, options) {
2012
2020
  });
2013
2021
  writtenFiles.push(hookFilePath);
2014
2022
  }
2015
- if (shouldCreateContext) {
2023
+ if (shouldCreateContext && (!existsSync(contextFilePath) || options.force)) {
2016
2024
  const contextContent = generateContextTemplate(featureComponentName);
2017
2025
  const hash = await writeFileWithSignature(contextFilePath, contextContent, getSignature(config, 'typescript'), config.hashing?.normalization);
2018
2026
  await registerFile(contextFilePath, {
@@ -2023,7 +2031,7 @@ async function addSectionCommand(route, featurePath, options) {
2023
2031
  });
2024
2032
  writtenFiles.push(contextFilePath);
2025
2033
  }
2026
- if (shouldCreateTests) {
2034
+ if (shouldCreateTests && (!existsSync(testFilePath) || options.force)) {
2027
2035
  const relativeFeaturePath = `./${path.basename(featureFilePath)}`;
2028
2036
  const testContent = generateTestTemplate(featureComponentName, relativeFeaturePath);
2029
2037
  const hash = await writeFileWithSignature(testFilePath, testContent, getSignature(config, 'typescript'), config.hashing?.normalization);
@@ -2035,7 +2043,7 @@ async function addSectionCommand(route, featurePath, options) {
2035
2043
  });
2036
2044
  writtenFiles.push(testFilePath);
2037
2045
  }
2038
- if (shouldCreateTypes) {
2046
+ if (shouldCreateTypes && (!existsSync(typesFilePath) || options.force)) {
2039
2047
  const typesContent = generateTypesTemplate(featureComponentName);
2040
2048
  const hash = await writeFileWithSignature(typesFilePath, typesContent, getSignature(config, 'typescript'), config.hashing?.normalization);
2041
2049
  await registerFile(typesFilePath, {
@@ -2046,7 +2054,7 @@ async function addSectionCommand(route, featurePath, options) {
2046
2054
  });
2047
2055
  writtenFiles.push(typesFilePath);
2048
2056
  }
2049
- if (shouldCreateReadme) {
2057
+ if (shouldCreateReadme && (!existsSync(readmeFilePath) || options.force)) {
2050
2058
  const readmeContent = generateReadmeTemplate(featureComponentName);
2051
2059
  const hash = await writeFileWithSignature(readmeFilePath, readmeContent, getSignature(config, 'astro'), config.hashing?.normalization);
2052
2060
  await registerFile(readmeFilePath, {
@@ -2057,7 +2065,7 @@ async function addSectionCommand(route, featurePath, options) {
2057
2065
  });
2058
2066
  writtenFiles.push(readmeFilePath);
2059
2067
  }
2060
- if (shouldCreateStories) {
2068
+ if (shouldCreateStories && (!existsSync(storiesFilePath) || options.force)) {
2061
2069
  const relativePath = `./${path.basename(featureFilePath)}`;
2062
2070
  const storiesContent = generateStoriesTemplate(featureComponentName, relativePath);
2063
2071
  const hash = await writeFileWithSignature(storiesFilePath, storiesContent, getSignature(config, 'typescript'), config.hashing?.normalization);
@@ -2870,30 +2878,37 @@ async function createComponentCommand(componentName, options) {
2870
2878
  console.log(` Sub-components: ${subComponentsDir}/`);
2871
2879
  return;
2872
2880
  }
2873
- await ensureNotExists(componentFilePath, options.force);
2874
- await ensureNotExists(indexFilePath, options.force);
2875
- if (shouldCreateContext)
2876
- await ensureNotExists(contextFilePath, options.force);
2877
- if (shouldCreateHook)
2878
- await ensureNotExists(hookFilePath, options.force);
2879
- if (shouldCreateTests)
2880
- await ensureNotExists(testFilePath, options.force);
2881
- if (shouldCreateConfig)
2882
- await ensureNotExists(configFilePath, options.force);
2883
- if (shouldCreateConstants)
2884
- await ensureNotExists(constantsFilePath, options.force);
2885
- if (shouldCreateTypes)
2886
- await ensureNotExists(typesFilePath, options.force);
2887
- if (shouldCreateApi)
2888
- await ensureNotExists(apiFilePath, options.force);
2889
- if (shouldCreateServices)
2890
- await ensureNotExists(servicesFilePath, options.force);
2891
- if (shouldCreateSchemas)
2892
- await ensureNotExists(schemasFilePath, options.force);
2893
- if (shouldCreateReadme)
2894
- await ensureNotExists(readmeFilePath, options.force);
2895
- if (shouldCreateStories)
2896
- await ensureNotExists(storiesFilePath, options.force);
2881
+ const componentExists = existsSync(componentFilePath);
2882
+ if (componentExists && !options.force) {
2883
+ console.log(`ℹ Component already exists at ${componentFilePath}. Entering additive mode.`);
2884
+ }
2885
+ // Check sub-items only if not in force mode
2886
+ if (!options.force) {
2887
+ if (existsSync(indexFilePath))
2888
+ console.log(` - Skipping existing index: ${indexFilePath}`);
2889
+ if (shouldCreateContext && existsSync(contextFilePath))
2890
+ console.log(` - Skipping existing context: ${contextFilePath}`);
2891
+ if (shouldCreateHook && existsSync(hookFilePath))
2892
+ console.log(` - Skipping existing hook: ${hookFilePath}`);
2893
+ if (shouldCreateTests && existsSync(testFilePath))
2894
+ console.log(` - Skipping existing test: ${testFilePath}`);
2895
+ if (shouldCreateConfig && existsSync(configFilePath))
2896
+ console.log(` - Skipping existing config: ${configFilePath}`);
2897
+ if (shouldCreateConstants && existsSync(constantsFilePath))
2898
+ console.log(` - Skipping existing constants: ${constantsFilePath}`);
2899
+ if (shouldCreateTypes && existsSync(typesFilePath))
2900
+ console.log(` - Skipping existing types: ${typesFilePath}`);
2901
+ if (shouldCreateApi && existsSync(apiFilePath))
2902
+ console.log(` - Skipping existing api: ${apiFilePath}`);
2903
+ if (shouldCreateServices && existsSync(servicesFilePath))
2904
+ console.log(` - Skipping existing services: ${servicesFilePath}`);
2905
+ if (shouldCreateSchemas && existsSync(schemasFilePath))
2906
+ console.log(` - Skipping existing schemas: ${schemasFilePath}`);
2907
+ if (shouldCreateReadme && existsSync(readmeFilePath))
2908
+ console.log(` - Skipping existing readme: ${readmeFilePath}`);
2909
+ if (shouldCreateStories && existsSync(storiesFilePath))
2910
+ console.log(` - Skipping existing stories: ${storiesFilePath}`);
2911
+ }
2897
2912
  await ensureDir(componentDir);
2898
2913
  if (shouldCreateSubComponentsDir)
2899
2914
  await ensureDir(subComponentsDir);
@@ -2917,24 +2932,29 @@ async function createComponentCommand(componentName, options) {
2917
2932
  await ensureDir(schemasDirInside);
2918
2933
  const componentContent = generateComponentTemplate(normalizedName, framework, config.naming.componentExtension);
2919
2934
  const signature = getSignature(config, config.naming.componentExtension === '.astro' ? 'astro' : 'tsx');
2920
- const componentHash = await writeFileWithSignature(componentFilePath, componentContent, signature, config.hashing?.normalization);
2921
- await registerFile(componentFilePath, {
2922
- kind: 'component',
2923
- template: 'component',
2924
- hash: componentHash,
2925
- owner: normalizedName
2926
- });
2927
- const writtenFiles = [componentFilePath];
2928
- const indexContent = generateIndexTemplate(normalizedName, config.naming.componentExtension);
2929
- const indexHash = await writeFileWithSignature(indexFilePath, indexContent, getSignature(config, 'typescript'), config.hashing?.normalization);
2930
- await registerFile(indexFilePath, {
2931
- kind: 'component-file',
2932
- template: 'index',
2933
- hash: indexHash,
2934
- owner: normalizedName
2935
- });
2936
- writtenFiles.push(indexFilePath);
2937
- if (shouldCreateTypes) {
2935
+ const writtenFiles = [];
2936
+ if (!componentExists || options.force) {
2937
+ const componentHash = await writeFileWithSignature(componentFilePath, componentContent, signature, config.hashing?.normalization);
2938
+ await registerFile(componentFilePath, {
2939
+ kind: 'component',
2940
+ template: 'component',
2941
+ hash: componentHash,
2942
+ owner: normalizedName
2943
+ });
2944
+ writtenFiles.push(componentFilePath);
2945
+ }
2946
+ if (!existsSync(indexFilePath) || options.force) {
2947
+ const indexContent = generateIndexTemplate(normalizedName, config.naming.componentExtension);
2948
+ const indexHash = await writeFileWithSignature(indexFilePath, indexContent, getSignature(config, 'typescript'), config.hashing?.normalization);
2949
+ await registerFile(indexFilePath, {
2950
+ kind: 'component-file',
2951
+ template: 'index',
2952
+ hash: indexHash,
2953
+ owner: normalizedName
2954
+ });
2955
+ writtenFiles.push(indexFilePath);
2956
+ }
2957
+ if (shouldCreateTypes && (!existsSync(typesFilePath) || options.force)) {
2938
2958
  const typesContent = generateTypesTemplate(normalizedName);
2939
2959
  const hash = await writeFileWithSignature(typesFilePath, typesContent, getSignature(config, 'typescript'), config.hashing?.normalization);
2940
2960
  await registerFile(typesFilePath, {
@@ -2945,7 +2965,7 @@ async function createComponentCommand(componentName, options) {
2945
2965
  });
2946
2966
  writtenFiles.push(typesFilePath);
2947
2967
  }
2948
- if (shouldCreateContext) {
2968
+ if (shouldCreateContext && (!existsSync(contextFilePath) || options.force)) {
2949
2969
  const contextContent = generateContextTemplate(normalizedName);
2950
2970
  const hash = await writeFileWithSignature(contextFilePath, contextContent, getSignature(config, 'typescript'), config.hashing?.normalization);
2951
2971
  await registerFile(contextFilePath, {
@@ -2956,7 +2976,7 @@ async function createComponentCommand(componentName, options) {
2956
2976
  });
2957
2977
  writtenFiles.push(contextFilePath);
2958
2978
  }
2959
- if (shouldCreateHook) {
2979
+ if (shouldCreateHook && (!existsSync(hookFilePath) || options.force)) {
2960
2980
  const hookName = getHookFunctionName(normalizedName);
2961
2981
  const hookContent = generateHookTemplate(normalizedName, hookName);
2962
2982
  const hash = await writeFileWithSignature(hookFilePath, hookContent, getSignature(config, 'typescript'), config.hashing?.normalization);
@@ -2968,7 +2988,7 @@ async function createComponentCommand(componentName, options) {
2968
2988
  });
2969
2989
  writtenFiles.push(hookFilePath);
2970
2990
  }
2971
- if (shouldCreateTests) {
2991
+ if (shouldCreateTests && (!existsSync(testFilePath) || options.force)) {
2972
2992
  const relativeComponentPath = `../${normalizedName}${config.naming.componentExtension}`;
2973
2993
  const testContent = generateTestTemplate(normalizedName, relativeComponentPath);
2974
2994
  const hash = await writeFileWithSignature(testFilePath, testContent, getSignature(config, 'typescript'), config.hashing?.normalization);
@@ -2980,7 +3000,7 @@ async function createComponentCommand(componentName, options) {
2980
3000
  });
2981
3001
  writtenFiles.push(testFilePath);
2982
3002
  }
2983
- if (shouldCreateConfig) {
3003
+ if (shouldCreateConfig && (!existsSync(configFilePath) || options.force)) {
2984
3004
  const configContent = generateConfigTemplate(normalizedName);
2985
3005
  const hash = await writeFileWithSignature(configFilePath, configContent, getSignature(config, 'typescript'), config.hashing?.normalization);
2986
3006
  await registerFile(configFilePath, {
@@ -2991,7 +3011,7 @@ async function createComponentCommand(componentName, options) {
2991
3011
  });
2992
3012
  writtenFiles.push(configFilePath);
2993
3013
  }
2994
- if (shouldCreateConstants) {
3014
+ if (shouldCreateConstants && (!existsSync(constantsFilePath) || options.force)) {
2995
3015
  const constantsContent = generateConstantsTemplate(normalizedName);
2996
3016
  const hash = await writeFileWithSignature(constantsFilePath, constantsContent, getSignature(config, 'typescript'), config.hashing?.normalization);
2997
3017
  await registerFile(constantsFilePath, {
@@ -3002,7 +3022,7 @@ async function createComponentCommand(componentName, options) {
3002
3022
  });
3003
3023
  writtenFiles.push(constantsFilePath);
3004
3024
  }
3005
- if (shouldCreateApi) {
3025
+ if (shouldCreateApi && (!existsSync(apiFilePath) || options.force)) {
3006
3026
  const apiContent = generateApiTemplate(normalizedName);
3007
3027
  const hash = await writeFileWithSignature(apiFilePath, apiContent, getSignature(config, 'typescript'), config.hashing?.normalization);
3008
3028
  await registerFile(apiFilePath, {
@@ -3013,7 +3033,7 @@ async function createComponentCommand(componentName, options) {
3013
3033
  });
3014
3034
  writtenFiles.push(apiFilePath);
3015
3035
  }
3016
- if (shouldCreateServices) {
3036
+ if (shouldCreateServices && (!existsSync(servicesFilePath) || options.force)) {
3017
3037
  const servicesContent = generateServiceTemplate(normalizedName);
3018
3038
  const hash = await writeFileWithSignature(servicesFilePath, servicesContent, getSignature(config, 'typescript'), config.hashing?.normalization);
3019
3039
  await registerFile(servicesFilePath, {
@@ -3024,7 +3044,7 @@ async function createComponentCommand(componentName, options) {
3024
3044
  });
3025
3045
  writtenFiles.push(servicesFilePath);
3026
3046
  }
3027
- if (shouldCreateSchemas) {
3047
+ if (shouldCreateSchemas && (!existsSync(schemasFilePath) || options.force)) {
3028
3048
  const schemasContent = generateSchemaTemplate(normalizedName);
3029
3049
  const hash = await writeFileWithSignature(schemasFilePath, schemasContent, getSignature(config, 'typescript'), config.hashing?.normalization);
3030
3050
  await registerFile(schemasFilePath, {
@@ -3035,7 +3055,7 @@ async function createComponentCommand(componentName, options) {
3035
3055
  });
3036
3056
  writtenFiles.push(schemasFilePath);
3037
3057
  }
3038
- if (shouldCreateReadme) {
3058
+ if (shouldCreateReadme && (!existsSync(readmeFilePath) || options.force)) {
3039
3059
  const readmeContent = generateReadmeTemplate(normalizedName);
3040
3060
  const hash = await writeFileWithSignature(readmeFilePath, readmeContent, getSignature(config, 'astro'), config.hashing?.normalization);
3041
3061
  await registerFile(readmeFilePath, {
@@ -3046,7 +3066,7 @@ async function createComponentCommand(componentName, options) {
3046
3066
  });
3047
3067
  writtenFiles.push(readmeFilePath);
3048
3068
  }
3049
- if (shouldCreateStories) {
3069
+ if (shouldCreateStories && (!existsSync(storiesFilePath) || options.force)) {
3050
3070
  const relativePath = `./${normalizedName}${config.naming.componentExtension}`;
3051
3071
  const storiesContent = generateStoriesTemplate(normalizedName, relativePath);
3052
3072
  const hash = await writeFileWithSignature(storiesFilePath, storiesContent, getSignature(config, 'typescript'), config.hashing?.normalization);
@@ -3624,7 +3644,24 @@ async function syncCommand(options) {
3624
3644
  }
3625
3645
  }
3626
3646
 
3627
- async function adoptCommand(identifier, options) {
3647
+ async function adoptCommand(kind, arg2, arg3, options) {
3648
+ // Handle cases where options is in a different position due to variable arguments
3649
+ if (typeof kind === 'object' && kind !== null && !Array.isArray(kind)) {
3650
+ options = kind;
3651
+ kind = undefined;
3652
+ arg2 = undefined;
3653
+ arg3 = undefined;
3654
+ }
3655
+ else if (typeof arg2 === 'object' && arg2 !== null && !Array.isArray(arg2)) {
3656
+ options = arg2;
3657
+ arg2 = undefined;
3658
+ arg3 = undefined;
3659
+ }
3660
+ else if (typeof arg3 === 'object' && arg3 !== null && !Array.isArray(arg3)) {
3661
+ options = arg3;
3662
+ arg3 = undefined;
3663
+ }
3664
+ options = options || {};
3628
3665
  try {
3629
3666
  const config = await loadConfig();
3630
3667
  const state = await loadState();
@@ -3634,6 +3671,9 @@ async function adoptCommand(identifier, options) {
3634
3671
  components: resolvePath(config, 'components')
3635
3672
  };
3636
3673
  let filesToAdopt = [];
3674
+ let identifier = kind;
3675
+ let customName = null;
3676
+ let sourcePath = null;
3637
3677
  if (!identifier && options.all) {
3638
3678
  // Adopt all untracked files in all roots
3639
3679
  const managedFiles = new Set();
@@ -3644,6 +3684,46 @@ async function adoptCommand(identifier, options) {
3644
3684
  }
3645
3685
  filesToAdopt = Array.from(managedFiles).filter(f => !state.files[f]);
3646
3686
  }
3687
+ else if (kind === 'component' && arg2) {
3688
+ const componentName = arg2;
3689
+ const untrackedFiles = new Set();
3690
+ const compPath = path.join(roots.components, componentName);
3691
+ if (existsSync(compPath)) {
3692
+ await scanDirectoryOrFile(compPath, untrackedFiles, state);
3693
+ }
3694
+ else {
3695
+ throw new Error(`Component directory not found: ${compPath}`);
3696
+ }
3697
+ filesToAdopt = Array.from(untrackedFiles);
3698
+ }
3699
+ else if (kind === 'feature' && arg2 && arg3) {
3700
+ sourcePath = arg2;
3701
+ customName = arg3;
3702
+ const targetPath = path.join(roots.features, customName);
3703
+ const absoluteSource = path.resolve(process.cwd(), sourcePath);
3704
+ const absoluteTarget = path.resolve(targetPath);
3705
+ if (existsSync(absoluteSource)) {
3706
+ if (!options.dryRun && absoluteSource !== absoluteTarget) {
3707
+ if (!existsSync(path.dirname(absoluteTarget))) {
3708
+ await mkdir(path.dirname(absoluteTarget), { recursive: true });
3709
+ }
3710
+ console.log(`Moving files from ${sourcePath} to ${path.relative(process.cwd(), targetPath)}...`);
3711
+ await rename(absoluteSource, absoluteTarget);
3712
+ sourcePath = path.relative(process.cwd(), targetPath);
3713
+ }
3714
+ else if (options.dryRun && absoluteSource !== absoluteTarget) {
3715
+ console.log(`Dry run: would move files from ${sourcePath} to ${path.relative(process.cwd(), targetPath)}`);
3716
+ sourcePath = path.relative(process.cwd(), targetPath);
3717
+ }
3718
+ const untrackedFiles = new Set();
3719
+ const fullPath = absoluteSource !== absoluteTarget && !options.dryRun ? absoluteTarget : absoluteSource;
3720
+ await scanDirectoryOrFile(fullPath, untrackedFiles, state);
3721
+ filesToAdopt = Array.from(untrackedFiles);
3722
+ }
3723
+ else {
3724
+ throw new Error(`Source path not found: ${absoluteSource}`);
3725
+ }
3726
+ }
3647
3727
  else if (identifier) {
3648
3728
  const untrackedFiles = new Set();
3649
3729
  // 1. Try as direct path
@@ -3985,5 +4065,59 @@ async function renameComponent(oldName, newName, options) {
3985
4065
  console.log(`✓ Renamed component ${normalizedOldName} to ${normalizedNewName}`);
3986
4066
  }
3987
4067
 
3988
- export { addSectionCommand, adoptCommand, createComponentCommand, initCommand, listSectionsCommand, moveSectionCommand, normalizeStateCommand, pruneMissingCommand, removeComponentCommand, removeSectionCommand, renameCommand, statusCommand, syncCommand, upgradeConfigCommand, validateStateCommand };
4068
+ /**
4069
+ * Add a new item (hook, api, service, etc.) to an existing feature or component.
4070
+ *
4071
+ * @param {string} itemType The type of item to add (e.g., 'api', 'hook', 'service')
4072
+ * @param {string} targetName The name of the feature or component
4073
+ * @param {Object} options Additional options from Commander
4074
+ */
4075
+ async function addItemCommand(itemType, targetName, options) {
4076
+ try {
4077
+ const state = await loadState();
4078
+ // Normalize itemType
4079
+ let normalizedItem = itemType.toLowerCase();
4080
+ if (normalizedItem === 'test')
4081
+ normalizedItem = 'tests';
4082
+ if (normalizedItem === 'service')
4083
+ normalizedItem = 'services';
4084
+ if (normalizedItem === 'schema')
4085
+ normalizedItem = 'schemas';
4086
+ if (normalizedItem === 'hook')
4087
+ normalizedItem = 'hooks'; // for add-section
4088
+ // Try to find as section (feature) first
4089
+ let section = findSection(state, targetName);
4090
+ let component = findComponent(state, targetName);
4091
+ // If not found by exact name, try to find by featurePath or part of it
4092
+ if (!section && !component) {
4093
+ section = state.sections.find(s => s.featurePath === targetName || s.featurePath.endsWith('/' + targetName));
4094
+ }
4095
+ if (!section && !component) {
4096
+ throw new Error(`Target not found in state: "${targetName}". Please use "add-section" or "create-component" directly if it's not managed by Textor.`);
4097
+ }
4098
+ const flags = { [normalizedItem]: true };
4099
+ // Also set singular for create-component which uses 'hook'
4100
+ if (normalizedItem === 'hooks')
4101
+ flags.hook = true;
4102
+ if (section) {
4103
+ console.log(`ℹ Adding ${normalizedItem} to feature: ${section.featurePath}`);
4104
+ return await addSectionCommand(undefined, section.featurePath, { ...options, ...flags });
4105
+ }
4106
+ if (component) {
4107
+ console.log(`ℹ Adding ${normalizedItem} to component: ${component.name}`);
4108
+ // For create-component, we might need to be careful with flags that are on by default
4109
+ // but getEffectiveOptions should handle it if we pass them explicitly as true.
4110
+ return await createComponentCommand(component.name, { ...options, ...flags });
4111
+ }
4112
+ }
4113
+ catch (error) {
4114
+ console.error('Error:', error.message);
4115
+ if (typeof process.exit === 'function' && process.env.NODE_ENV !== 'test') {
4116
+ process.exit(1);
4117
+ }
4118
+ throw error;
4119
+ }
4120
+ }
4121
+
4122
+ export { addItemCommand, addSectionCommand, adoptCommand, createComponentCommand, initCommand, listSectionsCommand, moveSectionCommand, normalizeStateCommand, pruneMissingCommand, removeComponentCommand, removeSectionCommand, renameCommand, statusCommand, syncCommand, upgradeConfigCommand, validateStateCommand };
3989
4123
  //# sourceMappingURL=index.js.map