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