@azure-net/cli 2.3.62 → 4.0.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/.prettierrc +7 -0
- package/bin/azure-net.js +247 -157
- package/bin/azure-net.ts +253 -0
- package/eslint.config.js +19 -0
- package/package.json +12 -5
- package/src/commands/generate/generateCrudBase.js +95 -114
- package/src/commands/generate/generateCrudPresenter.js +135 -142
- package/src/commands/generate/generateModule.js +21 -21
- package/src/commands/generate/generateModuleBase.js +92 -114
- package/src/commands/generate/generateModulePresenter.js +73 -80
- package/src/commands/generate/generatePresenter.js +38 -44
- package/src/commands/generate/generateRepository.js +41 -47
- package/src/commands/generate/generateSchema.js +74 -70
- package/src/commands/generate/generateService.js +32 -37
- package/src/commands/generate/index.js +0 -5
- package/src/generate/layers/generateRepository.js +124 -0
- package/src/generate/layers/generateRepositoryMethod.js +102 -0
- package/src/generate/layers/generateUseCases.js +50 -0
- package/src/generate/layers/repositoryShared.js +569 -0
- package/src/generate/module/generateDomain.js +146 -0
- package/src/generate/module/generateDomain.ts +147 -0
- package/src/generate/module/generateModule.js +84 -0
- package/src/generate/module/generateModule.ts +84 -0
- package/src/generate/module/generatePresenter.js +419 -0
- package/src/generate/module/generatePresenter.ts +442 -0
- package/src/generate/module/generateRepository.js +144 -0
- package/src/generate/module/generateRepository.ts +158 -0
- package/src/generate/module/generateSchemaFromType.js +320 -0
- package/src/generate/module/generateSchemaFromType.ts +325 -0
- package/src/generate/module/generateTypesJson.js +252 -0
- package/src/generate/module/generateTypesJson.ts +259 -0
- package/src/generate/module/generateUseCases.js +67 -0
- package/src/generate/module/generateUseCases.ts +67 -0
- package/src/generate/module/repositoryModuleShared.js +598 -0
- package/src/generate/ui/generateComponent.js +98 -0
- package/src/generate/ui/generateComponent.ts +100 -0
- package/src/generate/ui/generateDesignComponent.js +71 -0
- package/src/generate/ui/generateDesignComponent.ts +71 -0
- package/src/generate/ui/generateWidget.js +71 -0
- package/src/generate/ui/generateWidget.ts +71 -0
- package/src/init/initAliases.js +159 -0
- package/src/init/initAliases.ts +167 -0
- package/src/init/initEdges.js +74 -0
- package/src/init/initEdges.ts +74 -0
- package/src/init/initStructure.js +122 -0
- package/src/init/initStructure.ts +124 -0
- package/src/install/installFresh.js +101 -0
- package/src/install/installFresh.ts +101 -0
- package/src/plugins/addLint.js +257 -0
- package/src/plugins/addLint.ts +274 -0
- package/src/plugins/index.js +1 -0
- package/src/plugins/index.ts +1 -0
- package/src/scaffolds/createCoreMiddleware.js +27 -0
- package/src/scaffolds/createCoreMiddleware.ts +27 -0
- package/src/scaffolds/createCoreSchema.js +141 -0
- package/src/scaffolds/createCoreSchema.ts +142 -0
- package/src/scaffolds/createDatasource.js +173 -0
- package/src/scaffolds/createDatasource.ts +175 -0
- package/src/scaffolds/createDatasourceProvider.js +164 -0
- package/src/scaffolds/createDatasourceProvider.ts +175 -0
- package/src/scaffolds/createMiddleware.js +105 -0
- package/src/scaffolds/createMiddleware.ts +105 -0
- package/src/scaffolds/createPresenterFactory.js +112 -0
- package/src/scaffolds/createPresenterFactory.ts +114 -0
- package/src/scaffolds/createResponse.js +64 -0
- package/src/scaffolds/createResponse.ts +64 -0
- package/src/scaffolds/createSchemaRule.js +40 -0
- package/src/scaffolds/createSchemaRule.ts +42 -0
- package/src/scaffolds/createTranslationManager.js +78 -0
- package/src/scaffolds/createTranslationManager.ts +78 -0
- package/src/scaffolds/index.js +9 -0
- package/src/scaffolds/index.ts +9 -0
- package/src/utils/contextUtils.js +56 -49
- package/src/utils/fileUtils.js +72 -84
- package/src/utils/loadConfig.js +57 -13
- package/tsconfig.json +19 -0
- package/src/commands/generate/generateComponent.js +0 -53
- package/src/commands/generate/generateDatasource.js +0 -84
- package/src/commands/generate/generateDesignComponent.js +0 -53
- package/src/commands/generate/generateResponse.js +0 -41
- package/src/commands/generate/generateWidget.js +0 -53
- package/src/commands/init/index.js +0 -9
- package/src/commands/init/initAliases.js +0 -52
- package/src/commands/init/initEdges.js +0 -42
- package/src/commands/init/initLint.js +0 -138
- package/src/commands/init/initMiddleware.js +0 -21
- package/src/commands/init/initPresenter.js +0 -25
- package/src/commands/init/initSchema.js +0 -22
- package/src/commands/init/initStructure.js +0 -140
- package/src/commands/init/initTranslations.js +0 -59
- package/src/commands/init/migrateStructure.js +0 -144
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { loadUserConfig, resolveConfigFile } from '../utils/loadConfig.js';
|
|
4
|
+
|
|
5
|
+
const svelteConfigPath = path.resolve('svelte.config.js');
|
|
6
|
+
|
|
7
|
+
type ContextInput = string | { name?: string; alias?: string } | null | undefined;
|
|
8
|
+
type ContextConfig = { name: string; alias: string };
|
|
9
|
+
|
|
10
|
+
function normalizeAliasValue(value: unknown, fallbackName: string): string {
|
|
11
|
+
const raw = String(value ?? '').trim();
|
|
12
|
+
if (!raw.length) return `$${fallbackName}`;
|
|
13
|
+
return raw.startsWith('$') ? raw : `$${raw}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function normalizeContexts(rawContexts: unknown): ContextConfig[] {
|
|
17
|
+
if (!Array.isArray(rawContexts)) return [];
|
|
18
|
+
|
|
19
|
+
return (rawContexts as ContextInput[])
|
|
20
|
+
.map((item) => {
|
|
21
|
+
if (typeof item === 'string') {
|
|
22
|
+
const name = item.trim();
|
|
23
|
+
if (!name.length) return null;
|
|
24
|
+
return { name, alias: `$${name}` };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!item || typeof item !== 'object') return null;
|
|
28
|
+
|
|
29
|
+
const name = String(item.name ?? '').trim();
|
|
30
|
+
if (!name.length) return null;
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
name,
|
|
34
|
+
alias: normalizeAliasValue(item.alias, name)
|
|
35
|
+
};
|
|
36
|
+
})
|
|
37
|
+
.filter((item): item is ContextConfig => item !== null);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function generateAliases(config: { coreAlias?: string; contexts?: unknown }): {
|
|
41
|
+
coreAlias: string;
|
|
42
|
+
contexts: ContextConfig[];
|
|
43
|
+
aliases: Record<string, string>;
|
|
44
|
+
} {
|
|
45
|
+
const coreAlias = normalizeAliasValue(config.coreAlias, 'core');
|
|
46
|
+
const contexts = normalizeContexts(config.contexts);
|
|
47
|
+
|
|
48
|
+
const entries: Array<[string, string]> = [];
|
|
49
|
+
for (const context of contexts) {
|
|
50
|
+
entries.push([context.alias, `./src/app/${context.name}`]);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
entries.push([coreAlias, './src/core']);
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
coreAlias,
|
|
57
|
+
contexts,
|
|
58
|
+
aliases: Object.fromEntries(entries)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function parseAliasEntries(aliasBody: string): { ordered: string[]; map: Map<string, string> } {
|
|
63
|
+
const entryRegex = /(['"`])([^'"`]+)\1\s*:\s*(['"`])([^'"`]+)\3\s*,?/g;
|
|
64
|
+
const ordered: string[] = [];
|
|
65
|
+
const map = new Map<string, string>();
|
|
66
|
+
let match: RegExpExecArray | null;
|
|
67
|
+
|
|
68
|
+
while ((match = entryRegex.exec(aliasBody)) !== null) {
|
|
69
|
+
const key = match[2];
|
|
70
|
+
const value = match[4];
|
|
71
|
+
if (!key || !value) continue;
|
|
72
|
+
if (!map.has(key)) {
|
|
73
|
+
ordered.push(key);
|
|
74
|
+
}
|
|
75
|
+
map.set(key, value);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { ordered, map };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function buildAliasEntriesString(orderedKeys: string[], map: Map<string, string>, baseIndent: string): string {
|
|
82
|
+
if (!orderedKeys.length) return '';
|
|
83
|
+
|
|
84
|
+
return orderedKeys.map((key) => `${baseIndent}'${key}': '${map.get(key) ?? ''}'`).join(',\n');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function mergeAliasesInSvelteConfig(content: string, aliases: Record<string, string>): string {
|
|
88
|
+
const aliasRegex = /alias\s*:\s*\{([\s\S]*?)\}/m;
|
|
89
|
+
const aliasMatch = content.match(aliasRegex);
|
|
90
|
+
|
|
91
|
+
if (aliasMatch) {
|
|
92
|
+
const aliasBody = aliasMatch[1] ?? '';
|
|
93
|
+
const { ordered, map } = parseAliasEntries(aliasBody);
|
|
94
|
+
for (const [key, value] of Object.entries(aliases)) {
|
|
95
|
+
if (!map.has(key)) ordered.push(key);
|
|
96
|
+
map.set(key, value);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const baseIndentMatch = aliasBody.match(/\n(\s*)['"`]/);
|
|
100
|
+
const baseIndent = baseIndentMatch?.[1] ?? '\t\t\t';
|
|
101
|
+
const merged = buildAliasEntriesString(ordered, map, baseIndent);
|
|
102
|
+
const nextAliasBlock = `alias: {\n${merged}\n\t\t}`;
|
|
103
|
+
return content.replace(aliasRegex, nextAliasBlock);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const kitRegex = /kit\s*:\s*\{/m;
|
|
107
|
+
if (kitRegex.test(content)) {
|
|
108
|
+
const aliasLines = Object.entries(aliases)
|
|
109
|
+
.map(([key, value]) => `\t\t\t'${key}': '${value}'`)
|
|
110
|
+
.join(',\n');
|
|
111
|
+
const aliasBlock = `alias: {\n${aliasLines}\n\t\t},`;
|
|
112
|
+
return content.replace(kitRegex, `kit: {\n\t\t${aliasBlock}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return `${content}\n\n// azure-net aliases\nconst alias = {\n${Object.entries(aliases)
|
|
116
|
+
.map(([key, value]) => `\t'${key}': '${value}'`)
|
|
117
|
+
.join(',\n')}\n};\n`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function upsertCoreAlias(content: string, coreAlias: string): string {
|
|
121
|
+
const exportDefaultRegex = /export\s+default\s*\{([\s\S]*)\}\s*;?/m;
|
|
122
|
+
if (!exportDefaultRegex.test(content)) {
|
|
123
|
+
return `export default {\n\tcoreAlias: '${coreAlias}'\n};\n`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (/coreAlias\s*:/.test(content)) {
|
|
127
|
+
return content.replace(/coreAlias\s*:\s*['"`][^'"`]+['"`]/, `coreAlias: '${coreAlias}'`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return content.replace(exportDefaultRegex, (_full, body: string) => {
|
|
131
|
+
const trimmed = body.replace(/\s*$/, '');
|
|
132
|
+
if (!trimmed.length) {
|
|
133
|
+
return `export default {\n\tcoreAlias: '${coreAlias}'\n};`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const withComma = trimmed.endsWith(',') ? trimmed : `${trimmed},`;
|
|
137
|
+
return `export default {${withComma}\n\tcoreAlias: '${coreAlias}'\n};`;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export async function ensureCoreAliasInConfig(coreAlias: string): Promise<string> {
|
|
142
|
+
const { exists, filepath } = resolveConfigFile();
|
|
143
|
+
const aliasToSave = normalizeAliasValue(coreAlias, 'core');
|
|
144
|
+
const currentContent = exists ? await fs.readFile(filepath, 'utf-8') : '';
|
|
145
|
+
const nextContent = upsertCoreAlias(currentContent, aliasToSave);
|
|
146
|
+
await fs.writeFile(filepath, nextContent, 'utf-8');
|
|
147
|
+
return aliasToSave;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export default async function initAliases(): Promise<void> {
|
|
151
|
+
const config = await loadUserConfig();
|
|
152
|
+
const generated = generateAliases(config as { coreAlias?: string; contexts?: unknown });
|
|
153
|
+
const actualCoreAlias = await ensureCoreAliasInConfig(generated.coreAlias);
|
|
154
|
+
const aliases = { ...generated.aliases, [actualCoreAlias]: './src/core' };
|
|
155
|
+
|
|
156
|
+
let content: string;
|
|
157
|
+
try {
|
|
158
|
+
content = await fs.readFile(svelteConfigPath, 'utf-8');
|
|
159
|
+
} catch {
|
|
160
|
+
console.warn('⚠️ svelte.config.js not found, aliases were not updated');
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const nextContent = mergeAliasesInSvelteConfig(content, aliases);
|
|
165
|
+
await fs.writeFile(svelteConfigPath, nextContent, 'utf-8');
|
|
166
|
+
console.log('✅ Aliases updated in svelte.config.js');
|
|
167
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import fsSync from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const EDGES_IMPORT = `import { edgesPlugin } from '@azure-net/kit/edges/plugin';`;
|
|
6
|
+
|
|
7
|
+
function resolveViteConfigPath() {
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
const candidates = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs', 'vite.config.cjs'].map((filename) => path.join(cwd, filename));
|
|
10
|
+
|
|
11
|
+
for (const filepath of candidates) {
|
|
12
|
+
if (fsSync.existsSync(filepath)) {
|
|
13
|
+
return filepath;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function injectEdgesImport(content) {
|
|
21
|
+
if (content.includes(EDGES_IMPORT)) return content;
|
|
22
|
+
|
|
23
|
+
const svelteImportRegex = /import\s+\{\s*sveltekit\s*\}\s+from\s+['"]@sveltejs\/kit\/vite['"]\s*;?/m;
|
|
24
|
+
if (svelteImportRegex.test(content)) {
|
|
25
|
+
return content.replace(svelteImportRegex, (line) => `${line}\n${EDGES_IMPORT}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return `${EDGES_IMPORT}\n${content}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function injectEdgesPlugin(content) {
|
|
32
|
+
if (/edgesPlugin\s*\(\s*\)/.test(content)) return content;
|
|
33
|
+
|
|
34
|
+
const pluginsRegex = /plugins\s*:\s*\[([\s\S]*?)\]/m;
|
|
35
|
+
const pluginsMatch = content.match(pluginsRegex);
|
|
36
|
+
if (!pluginsMatch) {
|
|
37
|
+
throw new Error('plugins array was not found in vite.config');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const pluginsBody = pluginsMatch[1] ?? '';
|
|
41
|
+
let nextPluginsBody = pluginsBody;
|
|
42
|
+
|
|
43
|
+
if (/sveltekit\s*\(\s*\)/.test(pluginsBody)) {
|
|
44
|
+
nextPluginsBody = pluginsBody.replace(/sveltekit\s*\(\s*\)\s*,?/, (matched) => {
|
|
45
|
+
const hasComma = matched.trim().endsWith(',');
|
|
46
|
+
return hasComma ? `${matched} edgesPlugin(),` : `${matched}, edgesPlugin()`;
|
|
47
|
+
});
|
|
48
|
+
} else {
|
|
49
|
+
const trimmed = pluginsBody.trim();
|
|
50
|
+
if (!trimmed.length) {
|
|
51
|
+
nextPluginsBody = 'edgesPlugin()';
|
|
52
|
+
} else {
|
|
53
|
+
const withComma = /\s*,\s*$/.test(pluginsBody) ? pluginsBody : `${pluginsBody},`;
|
|
54
|
+
nextPluginsBody = `${withComma} edgesPlugin()`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return content.replace(pluginsRegex, `plugins: [${nextPluginsBody}]`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default async function initEdges() {
|
|
62
|
+
const viteConfigPath = resolveViteConfigPath();
|
|
63
|
+
if (!viteConfigPath) {
|
|
64
|
+
console.error('❌ vite.config.(ts|js|mjs|cjs) was not found');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let content = await fs.readFile(viteConfigPath, 'utf-8');
|
|
69
|
+
content = injectEdgesImport(content);
|
|
70
|
+
content = injectEdgesPlugin(content);
|
|
71
|
+
await fs.writeFile(viteConfigPath, content, 'utf-8');
|
|
72
|
+
|
|
73
|
+
console.log(`✅ Edges plugin initialized in ${path.basename(viteConfigPath)}`);
|
|
74
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import fsSync from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const EDGES_IMPORT = `import { edgesPlugin } from '@azure-net/kit/edges/plugin';`;
|
|
6
|
+
|
|
7
|
+
function resolveViteConfigPath(): string | null {
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
const candidates = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs', 'vite.config.cjs'].map((filename) => path.join(cwd, filename));
|
|
10
|
+
|
|
11
|
+
for (const filepath of candidates) {
|
|
12
|
+
if (fsSync.existsSync(filepath)) {
|
|
13
|
+
return filepath;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function injectEdgesImport(content: string): string {
|
|
21
|
+
if (content.includes(EDGES_IMPORT)) return content;
|
|
22
|
+
|
|
23
|
+
const svelteImportRegex = /import\s+\{\s*sveltekit\s*\}\s+from\s+['"]@sveltejs\/kit\/vite['"]\s*;?/m;
|
|
24
|
+
if (svelteImportRegex.test(content)) {
|
|
25
|
+
return content.replace(svelteImportRegex, (line) => `${line}\n${EDGES_IMPORT}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return `${EDGES_IMPORT}\n${content}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function injectEdgesPlugin(content: string): string {
|
|
32
|
+
if (/edgesPlugin\s*\(\s*\)/.test(content)) return content;
|
|
33
|
+
|
|
34
|
+
const pluginsRegex = /plugins\s*:\s*\[([\s\S]*?)\]/m;
|
|
35
|
+
const pluginsMatch = content.match(pluginsRegex);
|
|
36
|
+
if (!pluginsMatch) {
|
|
37
|
+
throw new Error('plugins array was not found in vite.config');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const pluginsBody = pluginsMatch[1] ?? '';
|
|
41
|
+
let nextPluginsBody = pluginsBody;
|
|
42
|
+
|
|
43
|
+
if (/sveltekit\s*\(\s*\)/.test(pluginsBody)) {
|
|
44
|
+
nextPluginsBody = pluginsBody.replace(/sveltekit\s*\(\s*\)\s*,?/, (matched) => {
|
|
45
|
+
const hasComma = matched.trim().endsWith(',');
|
|
46
|
+
return hasComma ? `${matched} edgesPlugin(),` : `${matched}, edgesPlugin()`;
|
|
47
|
+
});
|
|
48
|
+
} else {
|
|
49
|
+
const trimmed = pluginsBody.trim();
|
|
50
|
+
if (!trimmed.length) {
|
|
51
|
+
nextPluginsBody = 'edgesPlugin()';
|
|
52
|
+
} else {
|
|
53
|
+
const withComma = /\s*,\s*$/.test(pluginsBody) ? pluginsBody : `${pluginsBody},`;
|
|
54
|
+
nextPluginsBody = `${withComma} edgesPlugin()`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return content.replace(pluginsRegex, `plugins: [${nextPluginsBody}]`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default async function initEdges(): Promise<void> {
|
|
62
|
+
const viteConfigPath = resolveViteConfigPath();
|
|
63
|
+
if (!viteConfigPath) {
|
|
64
|
+
console.error('❌ vite.config.(ts|js|mjs|cjs) was not found');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let content = await fs.readFile(viteConfigPath, 'utf-8');
|
|
69
|
+
content = injectEdgesImport(content);
|
|
70
|
+
content = injectEdgesPlugin(content);
|
|
71
|
+
await fs.writeFile(viteConfigPath, content, 'utf-8');
|
|
72
|
+
|
|
73
|
+
console.log(`✅ Edges plugin initialized in ${path.basename(viteConfigPath)}`);
|
|
74
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
4
|
+
import initAliases, { normalizeContexts } from './initAliases.js';
|
|
5
|
+
|
|
6
|
+
const ROOT = path.join(process.cwd(), 'src');
|
|
7
|
+
const APP_ROOT = path.join(ROOT, 'app');
|
|
8
|
+
|
|
9
|
+
const CONTEXT_DIRS = [
|
|
10
|
+
'ui',
|
|
11
|
+
'layers',
|
|
12
|
+
'layers/domain',
|
|
13
|
+
'layers/application',
|
|
14
|
+
'layers/application/providers',
|
|
15
|
+
'layers/application/use-cases',
|
|
16
|
+
'layers/infrastructure',
|
|
17
|
+
'layers/infrastructure/providers',
|
|
18
|
+
'layers/infrastructure/http',
|
|
19
|
+
'layers/infrastructure/http/repositories',
|
|
20
|
+
'layers/presentation'
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const SHARED_DIRS = ['core'];
|
|
24
|
+
|
|
25
|
+
const ensureDir = async (dirPath) => {
|
|
26
|
+
try {
|
|
27
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.warn(`⚠️ Failed to create directory: ${dirPath}`, error);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const ensureFile = async (filePath, content) => {
|
|
34
|
+
try {
|
|
35
|
+
await fs.access(filePath);
|
|
36
|
+
return;
|
|
37
|
+
} catch {
|
|
38
|
+
// File is missing
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
43
|
+
await fs.writeFile(filePath, content, 'utf-8');
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.warn(`⚠️ Failed to create file: ${filePath}`, error);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const toPascalCase = (value) =>
|
|
50
|
+
value
|
|
51
|
+
.split(/[-_\s]+/)
|
|
52
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
53
|
+
.join('');
|
|
54
|
+
|
|
55
|
+
const createInfrastructureProvider = (contextName) => `import { createBoundaryProvider } from '@azure-net/kit';
|
|
56
|
+
|
|
57
|
+
export const ${contextName}InfrastructureProvider = createBoundaryProvider('${contextName}InfrastructureProvider', {
|
|
58
|
+
\tregister: () => ({})
|
|
59
|
+
});
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
const createApplicationProvider = (contextName) => `import { createBoundaryProvider } from '@azure-net/kit';
|
|
63
|
+
import { ${contextName}InfrastructureProvider } from '../../infrastructure/providers';
|
|
64
|
+
|
|
65
|
+
export const ${contextName}ApplicationProvider = createBoundaryProvider('${contextName}ApplicationProvider', {
|
|
66
|
+
\tdependsOn: { ${contextName}InfrastructureProvider },
|
|
67
|
+
\tregister: () => ({})
|
|
68
|
+
});
|
|
69
|
+
`;
|
|
70
|
+
|
|
71
|
+
const printContextsError = () => {
|
|
72
|
+
console.error('❌ Cannot generate folders structure: `contexts` is missing or empty in azure-net.config.ts/js');
|
|
73
|
+
console.error('Add contexts first, for example:');
|
|
74
|
+
console.error('export default {');
|
|
75
|
+
console.error("\tcontexts: ['web', 'admin']");
|
|
76
|
+
console.error('\t// or');
|
|
77
|
+
console.error("\t// contexts: [{ name: 'web', alias: '$web' }, { name: 'admin', alias: '$admin' }]");
|
|
78
|
+
console.error('};');
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const ensureContextStructure = async (context) => {
|
|
82
|
+
const contextRoot = path.join(APP_ROOT, context.name);
|
|
83
|
+
for (const dir of CONTEXT_DIRS) {
|
|
84
|
+
await ensureDir(path.join(contextRoot, dir));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const contextName = toPascalCase(context.name);
|
|
88
|
+
const infraProviderPath = path.join(contextRoot, 'layers', 'infrastructure', 'providers', 'InfrastructureProvider.ts');
|
|
89
|
+
const infraProviderIndex = path.join(contextRoot, 'layers', 'infrastructure', 'providers', 'index.ts');
|
|
90
|
+
const appProviderPath = path.join(contextRoot, 'layers', 'application', 'providers', 'ApplicationProvider.ts');
|
|
91
|
+
const appProviderIndex = path.join(contextRoot, 'layers', 'application', 'providers', 'index.ts');
|
|
92
|
+
const repositoriesIndex = path.join(contextRoot, 'layers', 'infrastructure', 'http', 'repositories', 'index.ts');
|
|
93
|
+
const useCasesIndex = path.join(contextRoot, 'layers', 'application', 'use-cases', 'index.ts');
|
|
94
|
+
|
|
95
|
+
await ensureFile(infraProviderPath, createInfrastructureProvider(contextName));
|
|
96
|
+
await ensureFile(infraProviderIndex, `export * from './InfrastructureProvider';\n`);
|
|
97
|
+
await ensureFile(appProviderPath, createApplicationProvider(contextName));
|
|
98
|
+
await ensureFile(appProviderIndex, `export * from './ApplicationProvider';\n`);
|
|
99
|
+
await ensureFile(repositoriesIndex, '');
|
|
100
|
+
await ensureFile(useCasesIndex, '');
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export default async function initStructure() {
|
|
104
|
+
const config = await loadUserConfig();
|
|
105
|
+
const contexts = normalizeContexts(config.contexts);
|
|
106
|
+
|
|
107
|
+
if (!contexts.length) {
|
|
108
|
+
printContextsError();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for (const sharedDir of SHARED_DIRS) {
|
|
113
|
+
await ensureDir(path.join(ROOT, sharedDir));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
for (const context of contexts) {
|
|
117
|
+
await ensureContextStructure(context);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
await initAliases();
|
|
121
|
+
console.log('✅ Folders structure initialized');
|
|
122
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
4
|
+
import initAliases, { normalizeContexts } from './initAliases.js';
|
|
5
|
+
|
|
6
|
+
type ContextConfig = { name: string; alias: string };
|
|
7
|
+
|
|
8
|
+
const ROOT = path.join(process.cwd(), 'src');
|
|
9
|
+
const APP_ROOT = path.join(ROOT, 'app');
|
|
10
|
+
|
|
11
|
+
const CONTEXT_DIRS = [
|
|
12
|
+
'ui',
|
|
13
|
+
'layers',
|
|
14
|
+
'layers/domain',
|
|
15
|
+
'layers/application',
|
|
16
|
+
'layers/application/providers',
|
|
17
|
+
'layers/application/use-cases',
|
|
18
|
+
'layers/infrastructure',
|
|
19
|
+
'layers/infrastructure/providers',
|
|
20
|
+
'layers/infrastructure/http',
|
|
21
|
+
'layers/infrastructure/http/repositories',
|
|
22
|
+
'layers/presentation'
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const SHARED_DIRS = ['core'];
|
|
26
|
+
|
|
27
|
+
const ensureDir = async (dirPath: string): Promise<void> => {
|
|
28
|
+
try {
|
|
29
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.warn(`⚠️ Failed to create directory: ${dirPath}`, error);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const ensureFile = async (filePath: string, content: string): Promise<void> => {
|
|
36
|
+
try {
|
|
37
|
+
await fs.access(filePath);
|
|
38
|
+
return;
|
|
39
|
+
} catch {
|
|
40
|
+
// File is missing
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
45
|
+
await fs.writeFile(filePath, content, 'utf-8');
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.warn(`⚠️ Failed to create file: ${filePath}`, error);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const toPascalCase = (value: string): string =>
|
|
52
|
+
value
|
|
53
|
+
.split(/[-_\s]+/)
|
|
54
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
55
|
+
.join('');
|
|
56
|
+
|
|
57
|
+
const createInfrastructureProvider = (contextName: string) => `import { createBoundaryProvider } from '@azure-net/kit';
|
|
58
|
+
|
|
59
|
+
export const ${contextName}InfrastructureProvider = createBoundaryProvider('${contextName}InfrastructureProvider', {
|
|
60
|
+
\tregister: () => ({})
|
|
61
|
+
});
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
const createApplicationProvider = (contextName: string) => `import { createBoundaryProvider } from '@azure-net/kit';
|
|
65
|
+
import { ${contextName}InfrastructureProvider } from '../../infrastructure/providers';
|
|
66
|
+
|
|
67
|
+
export const ${contextName}ApplicationProvider = createBoundaryProvider('${contextName}ApplicationProvider', {
|
|
68
|
+
\tdependsOn: { ${contextName}InfrastructureProvider },
|
|
69
|
+
\tregister: () => ({})
|
|
70
|
+
});
|
|
71
|
+
`;
|
|
72
|
+
|
|
73
|
+
const printContextsError = () => {
|
|
74
|
+
console.error('❌ Cannot generate folders structure: `contexts` is missing or empty in azure-net.config.ts/js');
|
|
75
|
+
console.error('Add contexts first, for example:');
|
|
76
|
+
console.error('export default {');
|
|
77
|
+
console.error("\tcontexts: ['web', 'admin']");
|
|
78
|
+
console.error('\t// or');
|
|
79
|
+
console.error("\t// contexts: [{ name: 'web', alias: '$web' }, { name: 'admin', alias: '$admin' }]");
|
|
80
|
+
console.error('};');
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const ensureContextStructure = async (context: ContextConfig): Promise<void> => {
|
|
84
|
+
const contextRoot = path.join(APP_ROOT, context.name);
|
|
85
|
+
for (const dir of CONTEXT_DIRS) {
|
|
86
|
+
await ensureDir(path.join(contextRoot, dir));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const contextName = toPascalCase(context.name);
|
|
90
|
+
const infraProviderPath = path.join(contextRoot, 'layers', 'infrastructure', 'providers', 'InfrastructureProvider.ts');
|
|
91
|
+
const infraProviderIndex = path.join(contextRoot, 'layers', 'infrastructure', 'providers', 'index.ts');
|
|
92
|
+
const appProviderPath = path.join(contextRoot, 'layers', 'application', 'providers', 'ApplicationProvider.ts');
|
|
93
|
+
const appProviderIndex = path.join(contextRoot, 'layers', 'application', 'providers', 'index.ts');
|
|
94
|
+
const repositoriesIndex = path.join(contextRoot, 'layers', 'infrastructure', 'http', 'repositories', 'index.ts');
|
|
95
|
+
const useCasesIndex = path.join(contextRoot, 'layers', 'application', 'use-cases', 'index.ts');
|
|
96
|
+
|
|
97
|
+
await ensureFile(infraProviderPath, createInfrastructureProvider(contextName));
|
|
98
|
+
await ensureFile(infraProviderIndex, `export * from './InfrastructureProvider';\n`);
|
|
99
|
+
await ensureFile(appProviderPath, createApplicationProvider(contextName));
|
|
100
|
+
await ensureFile(appProviderIndex, `export * from './ApplicationProvider';\n`);
|
|
101
|
+
await ensureFile(repositoriesIndex, '');
|
|
102
|
+
await ensureFile(useCasesIndex, '');
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export default async function initStructure(): Promise<void> {
|
|
106
|
+
const config = await loadUserConfig();
|
|
107
|
+
const contexts = normalizeContexts(config.contexts) as ContextConfig[];
|
|
108
|
+
|
|
109
|
+
if (!contexts.length) {
|
|
110
|
+
printContextsError();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
for (const sharedDir of SHARED_DIRS) {
|
|
115
|
+
await ensureDir(path.join(ROOT, sharedDir));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
for (const context of contexts) {
|
|
119
|
+
await ensureContextStructure(context);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
await initAliases();
|
|
123
|
+
console.log('✅ Folders structure initialized');
|
|
124
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import prompts from 'prompts';
|
|
2
|
+
import { addLint } from '../plugins/index.js';
|
|
3
|
+
import initEdges from '../init/initEdges.js';
|
|
4
|
+
import initStructure from '../init/initStructure.js';
|
|
5
|
+
import { normalizeContexts } from '../init/initAliases.js';
|
|
6
|
+
import { loadUserConfig } from '../utils/loadConfig.js';
|
|
7
|
+
import {
|
|
8
|
+
createCoreMiddleware,
|
|
9
|
+
createCoreSchema,
|
|
10
|
+
createDatasource,
|
|
11
|
+
createDatasourceProvider,
|
|
12
|
+
createMiddleware,
|
|
13
|
+
createPresenterFactory,
|
|
14
|
+
createResponse,
|
|
15
|
+
createTranslationManager
|
|
16
|
+
} from '../scaffolds/index.js';
|
|
17
|
+
|
|
18
|
+
const printContextsError = () => {
|
|
19
|
+
console.error('❌ Cannot run "install fresh": `contexts` is missing or empty in azure-net.config.ts/js');
|
|
20
|
+
console.error('Add contexts first, for example:');
|
|
21
|
+
console.error('export default {');
|
|
22
|
+
console.error("\tcontexts: ['web', 'admin']");
|
|
23
|
+
console.error('\t// or');
|
|
24
|
+
console.error("\t// contexts: [{ name: 'web', alias: '$web' }, { name: 'admin', alias: '$admin' }]");
|
|
25
|
+
console.error('};');
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const askConfirm = async (message) => {
|
|
29
|
+
const result = await prompts({
|
|
30
|
+
type: 'confirm',
|
|
31
|
+
name: 'confirmed',
|
|
32
|
+
message,
|
|
33
|
+
initial: true
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return Boolean(result.confirmed);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const runOptionalStep = async (question, action) => {
|
|
40
|
+
const shouldRun = await askConfirm(question);
|
|
41
|
+
if (!shouldRun) return;
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
await action();
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.warn(`⚠️ Step failed: ${question}`);
|
|
47
|
+
console.warn(error);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default async function installFresh() {
|
|
52
|
+
const config = await loadUserConfig();
|
|
53
|
+
const contexts = normalizeContexts(config.contexts);
|
|
54
|
+
|
|
55
|
+
if (!contexts.length) {
|
|
56
|
+
printContextsError();
|
|
57
|
+
process.exitCode = 1;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
await initStructure();
|
|
62
|
+
await initEdges();
|
|
63
|
+
|
|
64
|
+
await runOptionalStep('Add commit tools (lint/commit conventions)?', async () => {
|
|
65
|
+
await addLint();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await runOptionalStep('Create middleware manager?', async () => {
|
|
69
|
+
await createCoreMiddleware();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await runOptionalStep('Create starter middleware?', async () => {
|
|
73
|
+
await createMiddleware();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await runOptionalStep('Create schema factory?', async () => {
|
|
77
|
+
await createCoreSchema();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await runOptionalStep('Create presenter factory?', async () => {
|
|
81
|
+
await createPresenterFactory();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
await runOptionalStep('Create API response?', async () => {
|
|
85
|
+
await createResponse();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await runOptionalStep('Create datasource?', async () => {
|
|
89
|
+
await createDatasource();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
await runOptionalStep('Create datasource provider?', async () => {
|
|
93
|
+
await createDatasourceProvider();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
await runOptionalStep('Create translation manager (i18n)?', async () => {
|
|
97
|
+
await createTranslationManager();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
console.log('✅ install fresh completed');
|
|
101
|
+
}
|