@azure-net/cli 5.0.0-1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/azure-net.js +12 -45
- package/bin/azure-net.ts +13 -5
- package/package.json +1 -1
- package/src/checks/checkDomain.js +8 -38
- package/src/checks/checkFoldersStructure.js +0 -14
- package/src/checks/checkHooks.js +0 -5
- package/src/checks/checkImports.js +0 -1
- package/src/checks/checkInternal.js +2 -1
- package/src/checks/checkInternal.ts +2 -0
- package/src/checks/checkLayerBoundaries.js +50 -54
- package/src/checks/checkLayerBoundaries.ts +55 -58
- package/src/checks/checkLayerImports.js +136 -0
- package/src/checks/checkLayerImports.ts +185 -0
- package/src/checks/checkPresenterNames.js +1 -37
- package/src/checks/checkPresenterNames.ts +1 -6
- package/src/checks/checkProject.js +0 -6
- package/src/checks/checkProviderGraph.js +1 -38
- package/src/checks/checkProviderNames.js +0 -28
- package/src/checks/index.js +1 -1
- package/src/checks/index.ts +1 -0
- package/src/generate/layers/generateRepository.js +4 -19
- package/src/generate/layers/generateRepositoryMethod.js +0 -12
- package/src/generate/layers/generateUseCases.js +0 -6
- package/src/generate/layers/repositoryShared.js +41 -104
- package/src/generate/layers/repositoryShared.ts +17 -12
- package/src/generate/module/generateDomain.js +0 -25
- package/src/generate/module/generateModule.js +0 -10
- package/src/generate/module/generateModulePreset.js +10 -51
- package/src/generate/module/generateModulePreset.ts +9 -8
- package/src/generate/module/generatePresenter.js +29 -76
- package/src/generate/module/generatePresenter.ts +15 -10
- package/src/generate/module/generateRepository.js +0 -17
- package/src/generate/module/generateSchemaFromType.js +9 -58
- package/src/generate/module/generateSchemaFromType.ts +1 -2
- package/src/generate/module/generateTypesJson.js +4 -45
- package/src/generate/module/generateUseCases.js +0 -9
- package/src/generate/module/repositoryModuleShared.js +21 -98
- package/src/generate/module/repositoryModuleShared.ts +14 -10
- package/src/generate/ui/generateComponent.js +0 -16
- package/src/generate/ui/generateDesignComponent.js +0 -12
- package/src/generate/ui/generateWidget.js +0 -12
- package/src/init/initAliases.js +42 -64
- package/src/init/initAliases.ts +47 -42
- package/src/init/initEdges.js +0 -15
- package/src/init/initStructure.js +48 -21
- package/src/init/initStructure.ts +51 -3
- package/src/install/installFresh.js +0 -16
- package/src/plugins/addLint.js +11 -46
- package/src/scaffolds/createCoreSchema.js +6 -40
- package/src/scaffolds/createCoreSchema.ts +6 -18
- package/src/scaffolds/createDatasource.js +26 -61
- package/src/scaffolds/createDatasource.ts +26 -40
- package/src/scaffolds/createDatasourceProvider.js +19 -56
- package/src/scaffolds/createDatasourceProvider.ts +20 -34
- package/src/scaffolds/createPresenterFactory.js +5 -34
- package/src/scaffolds/createPresenterFactory.ts +5 -17
- package/src/scaffolds/createProgram.js +1 -5
- package/src/scaffolds/createResponse.js +3 -11
- package/src/scaffolds/createResponse.ts +3 -1
- package/src/scaffolds/createSchemaRule.js +3 -8
- package/src/scaffolds/createSchemaRule.ts +3 -1
- package/src/scaffolds/createTranslationManager.js +3 -14
- package/src/scaffolds/createTranslationManager.ts +3 -1
- package/src/utils/contextUtils.js +5 -20
- package/src/utils/contextUtils.ts +2 -3
- package/src/utils/fileUtils.js +3 -38
- package/src/utils/fileUtils.ts +0 -26
- package/src/utils/loadConfig.js +1 -14
- package/src/utils/loadConfig.ts +1 -3
- package/src/utils/sharedFoundation.js +48 -0
- package/src/utils/sharedFoundation.ts +70 -0
|
@@ -2,10 +2,9 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
4
4
|
import initAliases, { normalizeContexts } from './initAliases.js';
|
|
5
|
-
|
|
5
|
+
import { getSharedEssentialsPath } from '../utils/sharedFoundation.js';
|
|
6
6
|
const ROOT = path.join(process.cwd(), 'src');
|
|
7
7
|
const APP_ROOT = path.join(ROOT, 'app');
|
|
8
|
-
|
|
9
8
|
const CONTEXT_DIRS = [
|
|
10
9
|
'ui',
|
|
11
10
|
'layers',
|
|
@@ -19,9 +18,22 @@ const CONTEXT_DIRS = [
|
|
|
19
18
|
'layers/infrastructure/http/repositories',
|
|
20
19
|
'layers/presentation'
|
|
21
20
|
];
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const SHARED_ESSENTIALS_DIRS = [
|
|
22
|
+
'',
|
|
23
|
+
'foundation',
|
|
24
|
+
'foundation/abstracts',
|
|
25
|
+
'foundation/constants',
|
|
26
|
+
'foundation/constructs',
|
|
27
|
+
'foundation/constructs/datasource',
|
|
28
|
+
'foundation/constructs/presenter',
|
|
29
|
+
'foundation/constructs/provider',
|
|
30
|
+
'foundation/constructs/response',
|
|
31
|
+
'foundation/constructs/schema',
|
|
32
|
+
'foundation/constructs/schema/custom-rules',
|
|
33
|
+
'foundation/helpers',
|
|
34
|
+
'localization',
|
|
35
|
+
'pipelines'
|
|
36
|
+
];
|
|
25
37
|
const ensureDir = async (dirPath) => {
|
|
26
38
|
try {
|
|
27
39
|
await fs.mkdir(dirPath, { recursive: true });
|
|
@@ -29,7 +41,6 @@ const ensureDir = async (dirPath) => {
|
|
|
29
41
|
console.warn(`⚠️ Failed to create directory: ${dirPath}`, error);
|
|
30
42
|
}
|
|
31
43
|
};
|
|
32
|
-
|
|
33
44
|
const ensureFile = async (filePath, content) => {
|
|
34
45
|
try {
|
|
35
46
|
await fs.access(filePath);
|
|
@@ -37,7 +48,6 @@ const ensureFile = async (filePath, content) => {
|
|
|
37
48
|
} catch {
|
|
38
49
|
// File is missing
|
|
39
50
|
}
|
|
40
|
-
|
|
41
51
|
try {
|
|
42
52
|
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
43
53
|
await fs.writeFile(filePath, content, 'utf-8');
|
|
@@ -45,20 +55,17 @@ const ensureFile = async (filePath, content) => {
|
|
|
45
55
|
console.warn(`⚠️ Failed to create file: ${filePath}`, error);
|
|
46
56
|
}
|
|
47
57
|
};
|
|
48
|
-
|
|
49
58
|
const toPascalCase = (value) =>
|
|
50
59
|
value
|
|
51
60
|
.split(/[-_\s]+/)
|
|
52
61
|
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
53
62
|
.join('');
|
|
54
|
-
|
|
55
63
|
const createInfrastructureProvider = (contextName) => `import { createBoundaryProvider } from '@azure-net/kit';
|
|
56
64
|
|
|
57
65
|
export const ${contextName}InfrastructureProvider = createBoundaryProvider('${contextName}InfrastructureProvider', {
|
|
58
66
|
\tregister: () => ({})
|
|
59
67
|
});
|
|
60
68
|
`;
|
|
61
|
-
|
|
62
69
|
const createApplicationProvider = (contextName) => `import { createBoundaryProvider } from '@azure-net/kit';
|
|
63
70
|
import { ${contextName}InfrastructureProvider } from '../../infrastructure/providers';
|
|
64
71
|
|
|
@@ -67,7 +74,6 @@ export const ${contextName}ApplicationProvider = createBoundaryProvider('${conte
|
|
|
67
74
|
\tregister: () => ({})
|
|
68
75
|
});
|
|
69
76
|
`;
|
|
70
|
-
|
|
71
77
|
const printContextsError = () => {
|
|
72
78
|
console.error('❌ Cannot generate folders structure: `contexts` is missing or empty in azure-net.config.ts/js');
|
|
73
79
|
console.error('Add contexts first, for example:');
|
|
@@ -77,13 +83,32 @@ const printContextsError = () => {
|
|
|
77
83
|
console.error("\t// contexts: [{ name: 'web', alias: '$web' }, { name: 'admin', alias: '$admin' }]");
|
|
78
84
|
console.error('};');
|
|
79
85
|
};
|
|
80
|
-
|
|
86
|
+
const printSharedAliasError = () => {
|
|
87
|
+
console.error('❌ Cannot generate folders structure: `sharedAlias` is missing in azure-net.config.ts/js');
|
|
88
|
+
console.error('Add shared context and alias first, for example:');
|
|
89
|
+
console.error('export default {');
|
|
90
|
+
console.error("\tsharedAlias: '$shared-kernel',");
|
|
91
|
+
console.error("\tcontexts: [{ name: 'shared-kernel', alias: '$shared-kernel' }, 'public']");
|
|
92
|
+
console.error('};');
|
|
93
|
+
};
|
|
94
|
+
const ensureSharedEssentialsStructure = async (contexts, sharedAlias) => {
|
|
95
|
+
const normalizedSharedAlias = sharedAlias.startsWith('$') ? sharedAlias : `$${sharedAlias}`;
|
|
96
|
+
const sharedContext = contexts.find((context) => context.alias === normalizedSharedAlias);
|
|
97
|
+
if (!sharedContext) {
|
|
98
|
+
console.error(`❌ sharedAlias "${normalizedSharedAlias}" does not point to any configured context.`);
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
const essentialsRoot = getSharedEssentialsPath(sharedContext.name);
|
|
102
|
+
for (const dir of SHARED_ESSENTIALS_DIRS) {
|
|
103
|
+
await ensureDir(path.join(essentialsRoot, dir));
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
};
|
|
81
107
|
const ensureContextStructure = async (context) => {
|
|
82
108
|
const contextRoot = path.join(APP_ROOT, context.name);
|
|
83
109
|
for (const dir of CONTEXT_DIRS) {
|
|
84
110
|
await ensureDir(path.join(contextRoot, dir));
|
|
85
111
|
}
|
|
86
|
-
|
|
87
112
|
const contextName = toPascalCase(context.name);
|
|
88
113
|
const infraProviderPath = path.join(contextRoot, 'layers', 'infrastructure', 'providers', 'InfrastructureProvider.ts');
|
|
89
114
|
const infraProviderIndex = path.join(contextRoot, 'layers', 'infrastructure', 'providers', 'index.ts');
|
|
@@ -91,7 +116,6 @@ const ensureContextStructure = async (context) => {
|
|
|
91
116
|
const appProviderIndex = path.join(contextRoot, 'layers', 'application', 'providers', 'index.ts');
|
|
92
117
|
const repositoriesIndex = path.join(contextRoot, 'layers', 'infrastructure', 'http', 'repositories', 'index.ts');
|
|
93
118
|
const useCasesIndex = path.join(contextRoot, 'layers', 'application', 'use-cases', 'index.ts');
|
|
94
|
-
|
|
95
119
|
await ensureFile(infraProviderPath, createInfrastructureProvider(contextName));
|
|
96
120
|
await ensureFile(infraProviderIndex, `export * from './InfrastructureProvider';\n`);
|
|
97
121
|
await ensureFile(appProviderPath, createApplicationProvider(contextName));
|
|
@@ -99,24 +123,27 @@ const ensureContextStructure = async (context) => {
|
|
|
99
123
|
await ensureFile(repositoriesIndex, '');
|
|
100
124
|
await ensureFile(useCasesIndex, '');
|
|
101
125
|
};
|
|
102
|
-
|
|
103
126
|
export default async function initStructure() {
|
|
104
127
|
const config = await loadUserConfig();
|
|
105
128
|
const contexts = normalizeContexts(config.contexts);
|
|
106
|
-
|
|
107
129
|
if (!contexts.length) {
|
|
108
130
|
printContextsError();
|
|
109
131
|
return;
|
|
110
132
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
133
|
+
const sharedAlias = String(config.sharedAlias ?? '').trim();
|
|
134
|
+
if (!sharedAlias.length) {
|
|
135
|
+
printSharedAliasError();
|
|
136
|
+
process.exitCode = 1;
|
|
137
|
+
return;
|
|
114
138
|
}
|
|
115
|
-
|
|
116
139
|
for (const context of contexts) {
|
|
117
140
|
await ensureContextStructure(context);
|
|
118
141
|
}
|
|
119
|
-
|
|
142
|
+
const sharedCreated = await ensureSharedEssentialsStructure(contexts, sharedAlias);
|
|
143
|
+
if (!sharedCreated) {
|
|
144
|
+
process.exitCode = 1;
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
120
147
|
await initAliases();
|
|
121
148
|
console.log('✅ Folders structure initialized');
|
|
122
149
|
}
|
|
@@ -2,6 +2,7 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
4
4
|
import initAliases, { normalizeContexts } from './initAliases.js';
|
|
5
|
+
import { getSharedEssentialsPath } from '../utils/sharedFoundation.js';
|
|
5
6
|
|
|
6
7
|
type ContextConfig = { name: string; alias: string };
|
|
7
8
|
|
|
@@ -22,7 +23,19 @@ const CONTEXT_DIRS = [
|
|
|
22
23
|
'layers/presentation'
|
|
23
24
|
];
|
|
24
25
|
|
|
25
|
-
const
|
|
26
|
+
const SHARED_ESSENTIALS_DIRS = [
|
|
27
|
+
'',
|
|
28
|
+
'foundation',
|
|
29
|
+
'foundation/constructs',
|
|
30
|
+
'foundation/constructs/datasource',
|
|
31
|
+
'foundation/constructs/presenter',
|
|
32
|
+
'foundation/constructs/provider',
|
|
33
|
+
'foundation/constructs/response',
|
|
34
|
+
'foundation/constructs/schema',
|
|
35
|
+
'foundation/constructs/schema/custom-rules',
|
|
36
|
+
'localization',
|
|
37
|
+
'pipelines'
|
|
38
|
+
];
|
|
26
39
|
|
|
27
40
|
const ensureDir = async (dirPath: string): Promise<void> => {
|
|
28
41
|
try {
|
|
@@ -80,6 +93,32 @@ const printContextsError = () => {
|
|
|
80
93
|
console.error('};');
|
|
81
94
|
};
|
|
82
95
|
|
|
96
|
+
const printSharedAliasError = () => {
|
|
97
|
+
console.error('❌ Cannot generate folders structure: `sharedAlias` is missing in azure-net.config.ts/js');
|
|
98
|
+
console.error('Add shared context and alias first, for example:');
|
|
99
|
+
console.error('export default {');
|
|
100
|
+
console.error("\tsharedAlias: '$shared-kernel',");
|
|
101
|
+
console.error("\tcontexts: [{ name: 'shared-kernel', alias: '$shared-kernel' }, 'public']");
|
|
102
|
+
console.error('};');
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const ensureSharedEssentialsStructure = async (contexts: ContextConfig[], sharedAlias: string): Promise<boolean> => {
|
|
106
|
+
const normalizedSharedAlias = sharedAlias.startsWith('$') ? sharedAlias : `$${sharedAlias}`;
|
|
107
|
+
const sharedContext = contexts.find((context) => context.alias === normalizedSharedAlias);
|
|
108
|
+
|
|
109
|
+
if (!sharedContext) {
|
|
110
|
+
console.error(`❌ sharedAlias "${normalizedSharedAlias}" does not point to any configured context.`);
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const essentialsRoot = getSharedEssentialsPath(sharedContext.name);
|
|
115
|
+
for (const dir of SHARED_ESSENTIALS_DIRS) {
|
|
116
|
+
await ensureDir(path.join(essentialsRoot, dir));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return true;
|
|
120
|
+
};
|
|
121
|
+
|
|
83
122
|
const ensureContextStructure = async (context: ContextConfig): Promise<void> => {
|
|
84
123
|
const contextRoot = path.join(APP_ROOT, context.name);
|
|
85
124
|
for (const dir of CONTEXT_DIRS) {
|
|
@@ -111,14 +150,23 @@ export default async function initStructure(): Promise<void> {
|
|
|
111
150
|
return;
|
|
112
151
|
}
|
|
113
152
|
|
|
114
|
-
|
|
115
|
-
|
|
153
|
+
const sharedAlias = String(config.sharedAlias ?? '').trim();
|
|
154
|
+
if (!sharedAlias.length) {
|
|
155
|
+
printSharedAliasError();
|
|
156
|
+
process.exitCode = 1;
|
|
157
|
+
return;
|
|
116
158
|
}
|
|
117
159
|
|
|
118
160
|
for (const context of contexts) {
|
|
119
161
|
await ensureContextStructure(context);
|
|
120
162
|
}
|
|
121
163
|
|
|
164
|
+
const sharedCreated = await ensureSharedEssentialsStructure(contexts, sharedAlias);
|
|
165
|
+
if (!sharedCreated) {
|
|
166
|
+
process.exitCode = 1;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
122
170
|
await initAliases();
|
|
123
171
|
console.log('✅ Folders structure initialized');
|
|
124
172
|
}
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
createResponse,
|
|
14
14
|
createTranslationManager
|
|
15
15
|
} from '../scaffolds/index.js';
|
|
16
|
-
|
|
17
16
|
const printContextsError = () => {
|
|
18
17
|
console.error('❌ Cannot run "install fresh": `contexts` is missing or empty in azure-net.config.ts/js');
|
|
19
18
|
console.error('Add contexts first, for example:');
|
|
@@ -23,7 +22,6 @@ const printContextsError = () => {
|
|
|
23
22
|
console.error("\t// contexts: [{ name: 'web', alias: '$web' }, { name: 'admin', alias: '$admin' }]");
|
|
24
23
|
console.error('};');
|
|
25
24
|
};
|
|
26
|
-
|
|
27
25
|
const askConfirm = async (message) => {
|
|
28
26
|
const result = await prompts({
|
|
29
27
|
type: 'confirm',
|
|
@@ -31,14 +29,11 @@ const askConfirm = async (message) => {
|
|
|
31
29
|
message,
|
|
32
30
|
initial: true
|
|
33
31
|
});
|
|
34
|
-
|
|
35
32
|
return Boolean(result.confirmed);
|
|
36
33
|
};
|
|
37
|
-
|
|
38
34
|
const runOptionalStep = async (question, action) => {
|
|
39
35
|
const shouldRun = await askConfirm(question);
|
|
40
36
|
if (!shouldRun) return;
|
|
41
|
-
|
|
42
37
|
try {
|
|
43
38
|
await action();
|
|
44
39
|
} catch (error) {
|
|
@@ -46,48 +41,37 @@ const runOptionalStep = async (question, action) => {
|
|
|
46
41
|
console.warn(error);
|
|
47
42
|
}
|
|
48
43
|
};
|
|
49
|
-
|
|
50
44
|
export default async function installFresh() {
|
|
51
45
|
const config = await loadUserConfig();
|
|
52
46
|
const contexts = normalizeContexts(config.contexts);
|
|
53
|
-
|
|
54
47
|
if (!contexts.length) {
|
|
55
48
|
printContextsError();
|
|
56
49
|
process.exitCode = 1;
|
|
57
50
|
return;
|
|
58
51
|
}
|
|
59
|
-
|
|
60
52
|
await initStructure();
|
|
61
53
|
await initEdges();
|
|
62
54
|
await createProgram();
|
|
63
|
-
|
|
64
55
|
await runOptionalStep('Add commit tools (lint/commit conventions)?', async () => {
|
|
65
56
|
await addLint();
|
|
66
57
|
});
|
|
67
|
-
|
|
68
58
|
await runOptionalStep('Create schema factory?', async () => {
|
|
69
59
|
await createCoreSchema();
|
|
70
60
|
});
|
|
71
|
-
|
|
72
61
|
await runOptionalStep('Create presenter factory?', async () => {
|
|
73
62
|
await createPresenterFactory();
|
|
74
63
|
});
|
|
75
|
-
|
|
76
64
|
await runOptionalStep('Create API response?', async () => {
|
|
77
65
|
await createResponse();
|
|
78
66
|
});
|
|
79
|
-
|
|
80
67
|
await runOptionalStep('Create datasource?', async () => {
|
|
81
68
|
await createDatasource();
|
|
82
69
|
});
|
|
83
|
-
|
|
84
70
|
await runOptionalStep('Create datasource provider?', async () => {
|
|
85
71
|
await createDatasourceProvider();
|
|
86
72
|
});
|
|
87
|
-
|
|
88
73
|
await runOptionalStep('Create translation manager (i18n)?', async () => {
|
|
89
74
|
await createTranslationManager();
|
|
90
75
|
});
|
|
91
|
-
|
|
92
76
|
console.log('✅ install fresh completed');
|
|
93
77
|
}
|
package/src/plugins/addLint.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { execSync } from 'node:child_process';
|
|
4
|
-
|
|
5
4
|
const dependencies = ['@commitlint/cli', 'semantic-release', '@semantic-release/git', 'git-cz', 'husky', 'commitizen', 'env-cmd'];
|
|
6
|
-
|
|
7
5
|
const commitlintConfig = `export default {
|
|
8
6
|
rules: {
|
|
9
7
|
'body-leading-blank': [2, 'always'],
|
|
@@ -17,7 +15,6 @@ const commitlintConfig = `export default {
|
|
|
17
15
|
}
|
|
18
16
|
};
|
|
19
17
|
`;
|
|
20
|
-
|
|
21
18
|
const releaseConfig = `export default {
|
|
22
19
|
branches: ['main', 'dev'],
|
|
23
20
|
dryRun: false,
|
|
@@ -44,7 +41,6 @@ const releaseConfig = `export default {
|
|
|
44
41
|
]
|
|
45
42
|
};
|
|
46
43
|
`;
|
|
47
|
-
|
|
48
44
|
const prettierConfig = `{
|
|
49
45
|
"useTabs": true,
|
|
50
46
|
"singleQuote": true,
|
|
@@ -63,7 +59,6 @@ const prettierConfig = `{
|
|
|
63
59
|
]
|
|
64
60
|
}
|
|
65
61
|
`;
|
|
66
|
-
|
|
67
62
|
const resolveInstallCommand = (manager) => {
|
|
68
63
|
const deps = dependencies.join(' ');
|
|
69
64
|
switch (manager) {
|
|
@@ -75,11 +70,8 @@ const resolveInstallCommand = (manager) => {
|
|
|
75
70
|
return `yarn add -D ${deps}`;
|
|
76
71
|
case 'bun':
|
|
77
72
|
return `bun add -d ${deps}`;
|
|
78
|
-
default:
|
|
79
|
-
return `pnpm add -D ${deps}`;
|
|
80
73
|
}
|
|
81
74
|
};
|
|
82
|
-
|
|
83
75
|
const resolveRunScriptCommand = (manager, script) => {
|
|
84
76
|
switch (manager) {
|
|
85
77
|
case 'pnpm':
|
|
@@ -90,11 +82,8 @@ const resolveRunScriptCommand = (manager, script) => {
|
|
|
90
82
|
return `yarn ${script}`;
|
|
91
83
|
case 'bun':
|
|
92
84
|
return `bun run ${script}`;
|
|
93
|
-
default:
|
|
94
|
-
return `pnpm ${script}`;
|
|
95
85
|
}
|
|
96
86
|
};
|
|
97
|
-
|
|
98
87
|
const resolveHuskyCommand = (manager) => {
|
|
99
88
|
switch (manager) {
|
|
100
89
|
case 'pnpm':
|
|
@@ -105,11 +94,8 @@ const resolveHuskyCommand = (manager) => {
|
|
|
105
94
|
return 'yarn husky';
|
|
106
95
|
case 'bun':
|
|
107
96
|
return 'bunx husky';
|
|
108
|
-
default:
|
|
109
|
-
return 'pnpm exec husky';
|
|
110
97
|
}
|
|
111
98
|
};
|
|
112
|
-
|
|
113
99
|
const detectPackageManager = (cwd) => {
|
|
114
100
|
if (fs.existsSync(path.join(cwd, 'bun.lock')) || fs.existsSync(path.join(cwd, 'bun.lockb'))) return 'bun';
|
|
115
101
|
if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) return 'pnpm';
|
|
@@ -117,12 +103,10 @@ const detectPackageManager = (cwd) => {
|
|
|
117
103
|
if (fs.existsSync(path.join(cwd, 'package-lock.json'))) return 'npm';
|
|
118
104
|
return undefined;
|
|
119
105
|
};
|
|
120
|
-
|
|
121
106
|
const parseConfigState = (cwd) => {
|
|
122
107
|
const tsPath = path.join(cwd, 'azure-net.config.ts');
|
|
123
108
|
const jsPath = path.join(cwd, 'azure-net.config.js');
|
|
124
109
|
const configPath = fs.existsSync(tsPath) ? tsPath : fs.existsSync(jsPath) ? jsPath : null;
|
|
125
|
-
|
|
126
110
|
if (!configPath) {
|
|
127
111
|
return {
|
|
128
112
|
configPath: null,
|
|
@@ -131,77 +115,66 @@ const parseConfigState = (cwd) => {
|
|
|
131
115
|
validPackageManager: null
|
|
132
116
|
};
|
|
133
117
|
}
|
|
134
|
-
|
|
135
118
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
136
119
|
const hasPackageManagerKey = /packageManager\s*:/.test(content);
|
|
137
120
|
const managerMatch = content.match(/packageManager\s*:\s*['"`](bun|pnpm|npm|yarn)['"`]/);
|
|
138
|
-
const validPackageManager = managerMatch?.[1]
|
|
139
|
-
|
|
121
|
+
const validPackageManager = managerMatch?.[1];
|
|
140
122
|
return {
|
|
141
123
|
configPath,
|
|
142
124
|
content,
|
|
143
125
|
hasPackageManagerKey,
|
|
144
|
-
validPackageManager
|
|
126
|
+
validPackageManager: validPackageManager ?? null
|
|
145
127
|
};
|
|
146
128
|
};
|
|
147
|
-
|
|
148
129
|
const upsertPackageManagerInConfig = (content, manager) => {
|
|
149
130
|
const packageManagerEntry = `packageManager: '${manager}'`;
|
|
150
131
|
const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
|
|
151
|
-
|
|
152
132
|
if (!hasExportDefaultObject) {
|
|
153
133
|
return `export default {\n\t${packageManagerEntry}\n};\n`;
|
|
154
134
|
}
|
|
155
|
-
|
|
156
135
|
if (/packageManager\s*:/.test(content)) {
|
|
157
136
|
return content.replace(/packageManager\s*:\s*['"`][^'"`]+['"`]/, packageManagerEntry);
|
|
158
137
|
}
|
|
159
|
-
|
|
160
138
|
return content.replace(/export\s+default\s*\{([\s\S]*?)\}\s*;?/, (_full, body) => {
|
|
161
139
|
const trimmedRight = body.replace(/\s*$/, '');
|
|
162
140
|
if (!trimmedRight.length) {
|
|
163
141
|
return `export default {\n\t${packageManagerEntry}\n};`;
|
|
164
142
|
}
|
|
165
|
-
|
|
166
143
|
const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
|
|
167
144
|
return `export default {${withComma}\n\t${packageManagerEntry}\n};`;
|
|
168
145
|
});
|
|
169
146
|
};
|
|
170
|
-
|
|
171
147
|
const localOnlyPrepareScript = `node -e "const local = !process.env.CI && process.env.NODE_ENV !== 'production' && !process.env.DOCKER && !process.env.CONTAINER; process.exit(local ? 1 : 0)" || (husky && svelte-kit sync)`;
|
|
172
|
-
|
|
173
148
|
const selectPackageManager = async (cwd, preset) => {
|
|
174
149
|
if (preset) return preset;
|
|
175
150
|
const { default: prompts } = await import('prompts');
|
|
176
|
-
|
|
177
|
-
const order = ['bun', 'pnpm', 'npm', 'yarn'];
|
|
178
151
|
const detected = detectPackageManager(cwd);
|
|
179
152
|
const response = await prompts({
|
|
180
153
|
type: 'select',
|
|
181
154
|
name: 'manager',
|
|
182
155
|
message: 'Choose your package manager:',
|
|
183
|
-
choices:
|
|
184
|
-
|
|
156
|
+
choices: [
|
|
157
|
+
{ title: 'bun', value: 'bun' },
|
|
158
|
+
{ title: 'pnpm', value: 'pnpm' },
|
|
159
|
+
{ title: 'npm', value: 'npm' },
|
|
160
|
+
{ title: 'yarn', value: 'yarn' }
|
|
161
|
+
],
|
|
162
|
+
initial: detected ? ['bun', 'pnpm', 'npm', 'yarn'].indexOf(detected) : 0
|
|
185
163
|
});
|
|
186
|
-
|
|
187
164
|
if (!response.manager) {
|
|
188
165
|
throw new Error('Package manager is required');
|
|
189
166
|
}
|
|
190
167
|
return response.manager;
|
|
191
168
|
};
|
|
192
|
-
|
|
193
169
|
export default async function addLint(options = {}) {
|
|
194
170
|
const cwd = process.cwd();
|
|
195
171
|
const pkgPath = path.join(cwd, 'package.json');
|
|
196
|
-
|
|
197
172
|
if (!fs.existsSync(pkgPath)) {
|
|
198
173
|
console.error('❌ package.json not found in this directory');
|
|
199
174
|
process.exit(1);
|
|
200
175
|
}
|
|
201
|
-
|
|
202
176
|
const configState = parseConfigState(cwd);
|
|
203
177
|
const manager = configState.validPackageManager ?? (await selectPackageManager(cwd, options.manager));
|
|
204
|
-
|
|
205
178
|
if (!configState.configPath) {
|
|
206
179
|
const newConfigPath = path.join(cwd, 'azure-net.config.ts');
|
|
207
180
|
fs.writeFileSync(newConfigPath, `export default {\n\tpackageManager: '${manager}'\n};\n`);
|
|
@@ -209,49 +182,41 @@ export default async function addLint(options = {}) {
|
|
|
209
182
|
const nextConfig = upsertPackageManagerInConfig(configState.content ?? '', manager);
|
|
210
183
|
fs.writeFileSync(configState.configPath, nextConfig);
|
|
211
184
|
}
|
|
212
|
-
|
|
213
185
|
const installCommand = resolveInstallCommand(manager);
|
|
214
186
|
const runFormatCommand = resolveRunScriptCommand(manager, 'format');
|
|
215
187
|
const preCommitScript = `${resolveRunScriptCommand(manager, 'lint')} && ${resolveRunScriptCommand(manager, 'check')}`;
|
|
216
188
|
const commitScript = `${resolveRunScriptCommand(manager, 'format')} && git add . && git-cz && git push`;
|
|
217
189
|
const releaseScript = `${resolveRunScriptCommand(manager, 'commit')} && ${resolveRunScriptCommand(manager, 'semantic-release')}`;
|
|
218
|
-
|
|
219
190
|
console.log(`📦 Installing packages with ${manager}...`);
|
|
220
191
|
execSync(installCommand, { stdio: 'inherit' });
|
|
221
|
-
|
|
222
192
|
console.log('📁 Updating package.json...');
|
|
223
193
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
224
194
|
pkg.scripts = {
|
|
225
|
-
...(pkg.scripts
|
|
195
|
+
...(pkg.scripts ?? {}),
|
|
226
196
|
precommit: preCommitScript,
|
|
227
197
|
prepare: localOnlyPrepareScript,
|
|
228
198
|
'semantic-release': 'env-cmd semantic-release',
|
|
229
199
|
commit: commitScript,
|
|
230
200
|
release: releaseScript
|
|
231
201
|
};
|
|
232
|
-
|
|
233
|
-
pkg.config = pkg.config || {};
|
|
202
|
+
pkg.config = pkg.config ?? {};
|
|
234
203
|
pkg.config.commitizen = {
|
|
235
204
|
path: 'git-cz'
|
|
236
205
|
};
|
|
237
|
-
|
|
238
206
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4));
|
|
239
207
|
fs.writeFileSync(path.join(cwd, 'commitlint.config.ts'), commitlintConfig);
|
|
240
208
|
fs.writeFileSync(path.join(cwd, 'release.config.ts'), releaseConfig);
|
|
241
209
|
fs.writeFileSync(path.join(cwd, '.prettierrc'), prettierConfig);
|
|
242
|
-
|
|
243
210
|
console.log('🔧 Initializing Husky...');
|
|
244
211
|
try {
|
|
245
212
|
execSync(resolveHuskyCommand(manager), { stdio: 'inherit' });
|
|
246
213
|
} catch {
|
|
247
214
|
console.warn('⚠️ Husky initialization skipped (command failed in current environment).');
|
|
248
215
|
}
|
|
249
|
-
|
|
250
216
|
try {
|
|
251
217
|
execSync(runFormatCommand, { stdio: 'inherit' });
|
|
252
218
|
} catch {
|
|
253
219
|
console.warn('⚠️ Format script execution skipped (script may be missing).');
|
|
254
220
|
}
|
|
255
|
-
|
|
256
221
|
console.log(`✅ Linting and release setup completed! Added prepare script: ${localOnlyPrepareScript}`);
|
|
257
222
|
}
|
|
@@ -4,7 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import prompts from 'prompts';
|
|
5
5
|
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
6
6
|
import { toPascalCase } from '../utils/contextUtils.js';
|
|
7
|
-
|
|
7
|
+
import { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
8
8
|
const resolvePresetImportName = (preset) => {
|
|
9
9
|
switch (preset) {
|
|
10
10
|
case 'ru':
|
|
@@ -13,11 +13,8 @@ const resolvePresetImportName = (preset) => {
|
|
|
13
13
|
return 'validationMessagesEn';
|
|
14
14
|
case 'i18n':
|
|
15
15
|
return 'validationMessagesI18n';
|
|
16
|
-
default:
|
|
17
|
-
return 'validationMessagesI18n';
|
|
18
16
|
}
|
|
19
17
|
};
|
|
20
|
-
|
|
21
18
|
const createSchemaFactoryTemplate = (
|
|
22
19
|
factoryName,
|
|
23
20
|
messagesImportName
|
|
@@ -25,36 +22,27 @@ const createSchemaFactoryTemplate = (
|
|
|
25
22
|
|
|
26
23
|
export const ${factoryName} = createSchemaFactory(createRules(${messagesImportName}));
|
|
27
24
|
`;
|
|
28
|
-
|
|
29
25
|
const resolveConfigFile = (cwd) => {
|
|
30
26
|
const tsPath = path.join(cwd, 'azure-net.config.ts');
|
|
31
27
|
const jsPath = path.join(cwd, 'azure-net.config.js');
|
|
32
|
-
|
|
33
28
|
if (fsSync.existsSync(tsPath)) {
|
|
34
29
|
return { filepath: tsPath, type: 'ts', exists: true, content: fsSync.readFileSync(tsPath, 'utf-8') };
|
|
35
30
|
}
|
|
36
31
|
if (fsSync.existsSync(jsPath)) {
|
|
37
32
|
return { filepath: jsPath, type: 'js', exists: true, content: fsSync.readFileSync(jsPath, 'utf-8') };
|
|
38
33
|
}
|
|
39
|
-
|
|
40
34
|
return { filepath: tsPath, type: 'ts', exists: false, content: '' };
|
|
41
35
|
};
|
|
42
|
-
|
|
43
36
|
const buildDefaultSchemaFactoryConfigEntry = (factoryName) => {
|
|
44
37
|
return `defaultSchemaFactory: '${factoryName}'`;
|
|
45
38
|
};
|
|
46
|
-
|
|
47
39
|
const upsertDefaultSchemaFactoryConfig = (content, factoryName) => {
|
|
48
40
|
const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
|
|
49
41
|
const defaultFactoryEntry = buildDefaultSchemaFactoryConfigEntry(factoryName);
|
|
50
|
-
const coreAliasEntry = `coreAlias: '$core'`;
|
|
51
|
-
|
|
52
42
|
if (!hasExportDefaultObject) {
|
|
53
|
-
return `export default {\n\t${
|
|
43
|
+
return `export default {\n\t${defaultFactoryEntry}\n};\n`;
|
|
54
44
|
}
|
|
55
|
-
|
|
56
45
|
let nextContent = content;
|
|
57
|
-
|
|
58
46
|
if (/defaultSchemaFactory\s*:/.test(nextContent)) {
|
|
59
47
|
nextContent = nextContent.replace(/defaultSchemaFactory\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
|
|
60
48
|
} else if (/defaultSchema\s*:/.test(nextContent)) {
|
|
@@ -65,27 +53,12 @@ const upsertDefaultSchemaFactoryConfig = (content, factoryName) => {
|
|
|
65
53
|
if (!trimmedRight.length) {
|
|
66
54
|
return `export default {\n\t${defaultFactoryEntry}\n};`;
|
|
67
55
|
}
|
|
68
|
-
|
|
69
56
|
const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
|
|
70
57
|
return `export default {${withComma}\n\t${defaultFactoryEntry}\n};`;
|
|
71
58
|
});
|
|
72
59
|
}
|
|
73
|
-
|
|
74
|
-
if (/coreAlias\s*:/.test(nextContent)) {
|
|
75
|
-
return nextContent.replace(/coreAlias\s*:\s*['"`][^'"`]+['"`]/, coreAliasEntry);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return nextContent.replace(/export\s+default\s*\{([\s\S]*)\}\s*;?/, (_full, body) => {
|
|
79
|
-
const trimmedRight = body.replace(/\s*$/, '');
|
|
80
|
-
if (!trimmedRight.length) {
|
|
81
|
-
return `export default {\n\t${coreAliasEntry}\n};`;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
|
|
85
|
-
return `export default {${withComma}\n\t${coreAliasEntry}\n};`;
|
|
86
|
-
});
|
|
60
|
+
return nextContent;
|
|
87
61
|
};
|
|
88
|
-
|
|
89
62
|
export default async function createCoreSchema() {
|
|
90
63
|
const { schemaFactoryNameRaw } = await prompts({
|
|
91
64
|
type: 'text',
|
|
@@ -93,9 +66,7 @@ export default async function createCoreSchema() {
|
|
|
93
66
|
message: 'Schema factory name:',
|
|
94
67
|
initial: 'Schema'
|
|
95
68
|
});
|
|
96
|
-
|
|
97
69
|
const schemaFactoryName = toPascalCase(String(schemaFactoryNameRaw ?? 'Schema')) || 'Schema';
|
|
98
|
-
|
|
99
70
|
const { preset } = await prompts({
|
|
100
71
|
type: 'select',
|
|
101
72
|
name: 'preset',
|
|
@@ -107,33 +78,28 @@ export default async function createCoreSchema() {
|
|
|
107
78
|
],
|
|
108
79
|
initial: 2
|
|
109
80
|
});
|
|
110
|
-
|
|
111
81
|
const selectedPreset = preset ?? 'i18n';
|
|
112
82
|
const messagesImportName = resolvePresetImportName(selectedPreset);
|
|
113
|
-
const
|
|
83
|
+
const { sharedContext } = await getSharedState();
|
|
84
|
+
const coreSchemaPath = getFoundationConstructPath(sharedContext.name, 'schema');
|
|
114
85
|
const customRulesPath = path.join(coreSchemaPath, 'custom-rules');
|
|
115
86
|
const filePath = path.join(coreSchemaPath, `${schemaFactoryName}.ts`);
|
|
116
|
-
|
|
117
87
|
await fs.mkdir(coreSchemaPath, { recursive: true });
|
|
118
88
|
await fs.mkdir(customRulesPath, { recursive: true });
|
|
119
|
-
|
|
120
89
|
const created = await writeIfNotExists(filePath, createSchemaFactoryTemplate(schemaFactoryName, messagesImportName));
|
|
121
90
|
if (!created) {
|
|
122
91
|
console.log(`⚠️ Schema factory "${schemaFactoryName}" already exists. File was not overwritten.`);
|
|
123
92
|
} else {
|
|
124
93
|
await updateIndexTs(coreSchemaPath);
|
|
125
|
-
console.log(`✅
|
|
94
|
+
console.log(`✅ Shared schema factory created: ${filePath}`);
|
|
126
95
|
}
|
|
127
|
-
|
|
128
96
|
const { useAsDefault } = await prompts({
|
|
129
97
|
type: 'confirm',
|
|
130
98
|
name: 'useAsDefault',
|
|
131
99
|
message: 'Use this schema factory as default for the project?',
|
|
132
100
|
initial: true
|
|
133
101
|
});
|
|
134
|
-
|
|
135
102
|
if (!useAsDefault) return;
|
|
136
|
-
|
|
137
103
|
const config = resolveConfigFile(process.cwd());
|
|
138
104
|
const nextContent = upsertDefaultSchemaFactoryConfig(config.content, schemaFactoryName);
|
|
139
105
|
await fs.writeFile(config.filepath, nextContent, 'utf-8');
|