@azure-net/cli 5.1.1 → 6.0.0-next.3
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 +201 -0
- package/bin/azure-net.js +236 -221
- package/dist/bin/azure-net.d.ts +2 -0
- package/dist/src/checks/architecture.d.ts +20 -0
- package/dist/src/checks/checkDomain.d.ts +1 -0
- package/dist/src/checks/checkFoldersStructure.d.ts +1 -0
- package/dist/src/checks/checkHooks.d.ts +1 -0
- package/dist/src/checks/checkImports.d.ts +1 -0
- package/dist/src/checks/checkInternal.d.ts +1 -0
- package/dist/src/checks/checkLayerBoundaries.d.ts +1 -0
- package/dist/src/checks/checkLayerImports.d.ts +1 -0
- package/dist/src/checks/checkPresenterNames.d.ts +1 -0
- package/dist/src/checks/checkProject.d.ts +1 -0
- package/dist/src/checks/checkProviderGraph.d.ts +1 -0
- package/dist/src/checks/checkProviderNames.d.ts +1 -0
- package/dist/src/generate/layers/generateRepository.d.ts +1 -0
- package/dist/src/generate/layers/generateRepositoryMethod.d.ts +1 -0
- package/dist/src/generate/layers/generateUseCases.d.ts +1 -0
- package/dist/src/generate/module/generateDomain.d.ts +8 -0
- package/dist/src/generate/module/generateModule.d.ts +1 -0
- package/dist/src/generate/module/generateModulePreset.d.ts +1 -0
- package/dist/src/generate/module/generatePresenter.d.ts +29 -0
- package/dist/src/generate/module/generateRepository.d.ts +15 -0
- package/dist/src/generate/module/generateRepositoryMethod.d.ts +2 -0
- package/dist/src/generate/module/generateSchemaFromType.d.ts +9 -0
- package/dist/src/generate/module/generateStore.d.ts +1 -0
- package/dist/src/generate/module/generateTypesJson.d.ts +2 -0
- package/dist/src/generate/module/generateUseCases.d.ts +1 -0
- package/dist/src/generate/module/repositoryModuleShared.d.ts +89 -0
- package/dist/src/generate/routes/generateRoutes.d.ts +14 -0
- package/dist/src/generate/ui/generateComponent.d.ts +1 -0
- package/dist/src/generate/ui/generateDesignComponent.d.ts +1 -0
- package/dist/src/generate/ui/generateWidget.d.ts +1 -0
- package/dist/src/git/commit.d.ts +23 -0
- package/dist/src/git/push.d.ts +11 -0
- package/dist/src/git/runGit.d.ts +2 -0
- package/dist/src/init/initAliases.d.ts +12 -0
- package/dist/src/init/initEdges.d.ts +2 -0
- package/dist/src/init/initStructure.d.ts +1 -0
- package/dist/src/install/configureCommitTools.d.ts +1 -0
- package/dist/src/install/installFresh.d.ts +1 -0
- package/dist/src/migrate/migrate.d.ts +22 -0
- package/dist/src/migrate/presenterFactories.d.ts +9 -0
- package/dist/src/migrate/presenters.d.ts +13 -0
- package/dist/src/migrate/translations.d.ts +8 -0
- package/dist/src/plugins/addLint.d.ts +5 -0
- package/dist/src/scaffolds/createCoreSchema.d.ts +1 -0
- package/dist/src/scaffolds/createDatasource.d.ts +1 -0
- package/dist/src/scaffolds/createProgram.d.ts +1 -0
- package/dist/src/scaffolds/createResponse.d.ts +1 -0
- package/dist/src/scaffolds/createSchemaRule.d.ts +1 -0
- package/dist/src/scaffolds/createTranslationManager.d.ts +1 -0
- package/{src/scaffolds/index.ts → dist/src/scaffolds/index.d.ts} +0 -2
- package/dist/src/scaffolds/registerDatasource.d.ts +2 -0
- package/dist/src/scaffolds/updateDefaultFactoryConfig.d.ts +1 -0
- package/dist/src/utils/architecture.d.ts +31 -0
- package/dist/src/utils/contextUtils.d.ts +6 -0
- package/dist/src/utils/fileUtils.d.ts +5 -0
- package/dist/src/utils/flattenConfig.d.ts +2 -0
- package/dist/src/utils/legacyAliases.d.ts +1 -0
- package/dist/src/utils/loadConfig.d.ts +16 -0
- package/dist/src/utils/packageImports.d.ts +4 -0
- package/dist/src/utils/sharedFoundation.d.ts +20 -0
- package/dist/src/utils/viteConfig.d.ts +9 -0
- package/package.json +17 -7
- package/src/checks/architecture.js +154 -0
- package/src/checks/checkDomain.js +124 -154
- package/src/checks/checkFoldersStructure.js +64 -52
- package/src/checks/checkHooks.js +12 -12
- package/src/checks/checkImports.js +26 -142
- package/src/checks/checkInternal.js +27 -24
- package/src/checks/checkLayerBoundaries.js +22 -197
- package/src/checks/checkLayerImports.js +14 -134
- package/src/checks/checkPresenterNames.js +156 -143
- package/src/checks/checkProject.js +27 -26
- package/src/checks/checkProviderGraph.js +182 -166
- package/src/checks/checkProviderNames.js +123 -112
- package/src/generate/layers/generateRepository.js +1 -109
- package/src/generate/layers/generateRepositoryMethod.js +1 -90
- package/src/generate/layers/generateUseCases.js +1 -44
- package/src/generate/module/generateDomain.js +81 -105
- package/src/generate/module/generateModule.js +34 -68
- package/src/generate/module/generateModulePreset.js +188 -248
- package/src/generate/module/generatePresenter.js +441 -369
- package/src/generate/module/generateRepository.js +102 -121
- package/src/generate/module/generateRepositoryMethod.js +117 -0
- package/src/generate/module/generateSchemaFromType.js +283 -280
- package/src/generate/module/generateStore.js +41 -0
- package/src/generate/module/generateTypesJson.js +196 -195
- package/src/generate/module/generateUseCases.js +47 -55
- package/src/generate/module/repositoryModuleShared.js +480 -459
- package/src/generate/routes/generateRoutes.js +4 -7
- package/src/generate/ui/generateComponent.js +44 -64
- package/src/generate/ui/generateDesignComponent.js +21 -41
- package/src/generate/ui/generateWidget.js +21 -41
- package/src/git/commit.js +67 -0
- package/src/git/push.js +19 -0
- package/src/git/runGit.js +11 -0
- package/src/init/initAliases.js +19 -135
- package/src/init/initEdges.js +79 -54
- package/src/init/initStructure.js +31 -145
- package/src/install/configureCommitTools.js +1 -0
- package/src/install/installFresh.js +39 -68
- package/src/migrate/migrate.js +1027 -0
- package/src/migrate/presenterFactories.js +189 -0
- package/src/migrate/presenters.js +373 -0
- package/src/migrate/translations.js +213 -0
- package/src/plugins/addLint.js +52 -219
- package/src/scaffolds/createCoreSchema.js +65 -91
- package/src/scaffolds/createDatasource.js +67 -101
- package/src/scaffolds/createProgram.js +8 -8
- package/src/scaffolds/createResponse.js +29 -29
- package/src/scaffolds/createSchemaRule.js +19 -19
- package/src/scaffolds/createTranslationManager.js +84 -37
- package/src/scaffolds/index.js +0 -2
- package/src/scaffolds/registerDatasource.js +59 -0
- package/src/scaffolds/updateDefaultFactoryConfig.js +31 -0
- package/src/utils/architecture.js +145 -0
- package/src/utils/contextUtils.js +32 -65
- package/src/utils/fileUtils.js +69 -50
- package/src/utils/flattenConfig.js +38 -0
- package/src/utils/legacyAliases.js +75 -0
- package/src/utils/loadConfig.js +76 -40
- package/src/utils/packageImports.js +63 -0
- package/src/utils/sharedFoundation.js +36 -42
- package/src/utils/viteConfig.js +295 -0
- package/.prettierrc +0 -7
- package/bin/azure-net.ts +0 -308
- package/eslint.config.js +0 -34
- package/src/checks/checkDomain.ts +0 -223
- package/src/checks/checkFoldersStructure.ts +0 -85
- package/src/checks/checkHooks.ts +0 -22
- package/src/checks/checkImports.ts +0 -193
- package/src/checks/checkInternal.ts +0 -48
- package/src/checks/checkLayerBoundaries.ts +0 -255
- package/src/checks/checkLayerImports.ts +0 -185
- package/src/checks/checkPresenterNames.ts +0 -203
- package/src/checks/checkProject.ts +0 -45
- package/src/checks/checkProviderGraph.ts +0 -234
- package/src/checks/checkProviderNames.ts +0 -165
- package/src/generate/layers/generateRepository.ts +0 -123
- package/src/generate/layers/generateRepositoryMethod.ts +0 -102
- package/src/generate/layers/generateUseCases.ts +0 -50
- package/src/generate/layers/repositoryShared.js +0 -506
- package/src/generate/layers/repositoryShared.ts +0 -662
- package/src/generate/module/generateDomain.ts +0 -147
- package/src/generate/module/generateModule.ts +0 -84
- package/src/generate/module/generateModulePreset.ts +0 -338
- package/src/generate/module/generatePresenter.ts +0 -498
- package/src/generate/module/generateRepository.ts +0 -158
- package/src/generate/module/generateSchemaFromType.ts +0 -368
- package/src/generate/module/generateTypesJson.ts +0 -259
- package/src/generate/module/generateUseCases.ts +0 -67
- package/src/generate/module/repositoryModuleShared.ts +0 -669
- package/src/generate/routes/generateRoutes.ts +0 -275
- package/src/generate/ui/generateComponent.ts +0 -100
- package/src/generate/ui/generateDesignComponent.ts +0 -71
- package/src/generate/ui/generateWidget.ts +0 -71
- package/src/init/initAliases.ts +0 -172
- package/src/init/initEdges.ts +0 -74
- package/src/init/initStructure.ts +0 -172
- package/src/install/installFresh.ts +0 -93
- package/src/plugins/addLint.ts +0 -274
- package/src/scaffolds/createCoreSchema.ts +0 -130
- package/src/scaffolds/createDatasource.ts +0 -161
- package/src/scaffolds/createDatasourceProvider.js +0 -127
- package/src/scaffolds/createDatasourceProvider.ts +0 -161
- package/src/scaffolds/createPresenterFactory.js +0 -83
- package/src/scaffolds/createPresenterFactory.ts +0 -102
- package/src/scaffolds/createProgram.ts +0 -19
- package/src/scaffolds/createResponse.ts +0 -66
- package/src/scaffolds/createSchemaRule.ts +0 -44
- package/src/scaffolds/createTranslationManager.ts +0 -80
- package/src/utils/contextUtils.ts +0 -88
- package/src/utils/fileUtils.ts +0 -74
- package/src/utils/loadConfig.ts +0 -68
- package/src/utils/sharedFoundation.ts +0 -70
- package/tsconfig.json +0 -19
- /package/{src/checks/index.ts → dist/src/checks/index.d.ts} +0 -0
- /package/{src/plugins/index.ts → dist/src/plugins/index.d.ts} +0 -0
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import fsSync from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import prompts from 'prompts';
|
|
5
|
-
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
6
|
-
import { toPascalCase } from '../utils/contextUtils.js';
|
|
7
|
-
import { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
8
|
-
|
|
9
|
-
type ConfigPath = 'ts' | 'js';
|
|
10
|
-
|
|
11
|
-
const createPresenterFactoryTemplate = (
|
|
12
|
-
factoryName: string
|
|
13
|
-
): string => `import { createAsyncHelpers, createPresenterFactory } from '@azure-net/kit/delivery';
|
|
14
|
-
|
|
15
|
-
export const AsyncHelpers = createAsyncHelpers();
|
|
16
|
-
|
|
17
|
-
export const ${factoryName} = createPresenterFactory({ ...AsyncHelpers });
|
|
18
|
-
`;
|
|
19
|
-
|
|
20
|
-
const resolveConfigFile = (cwd: string): { filepath: string; type: ConfigPath; exists: boolean; content: string } => {
|
|
21
|
-
const tsPath = path.join(cwd, 'azure-net.config.ts');
|
|
22
|
-
const jsPath = path.join(cwd, 'azure-net.config.js');
|
|
23
|
-
|
|
24
|
-
if (fsSync.existsSync(tsPath)) {
|
|
25
|
-
return { filepath: tsPath, type: 'ts', exists: true, content: fsSync.readFileSync(tsPath, 'utf-8') };
|
|
26
|
-
}
|
|
27
|
-
if (fsSync.existsSync(jsPath)) {
|
|
28
|
-
return { filepath: jsPath, type: 'js', exists: true, content: fsSync.readFileSync(jsPath, 'utf-8') };
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return { filepath: tsPath, type: 'ts', exists: false, content: '' };
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const buildDefaultPresenterFactoryConfigEntry = (factoryName: string): string => {
|
|
35
|
-
return `defaultPresenterFactory: '${factoryName}'`;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const upsertDefaultPresenterFactoryConfig = (content: string, factoryName: string): string => {
|
|
39
|
-
const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
|
|
40
|
-
const defaultFactoryEntry = buildDefaultPresenterFactoryConfigEntry(factoryName);
|
|
41
|
-
|
|
42
|
-
if (!hasExportDefaultObject) {
|
|
43
|
-
return `export default {\n\t${defaultFactoryEntry}\n};\n`;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
let nextContent = content;
|
|
47
|
-
|
|
48
|
-
if (/defaultPresenterFactory\s*:/.test(nextContent)) {
|
|
49
|
-
nextContent = nextContent.replace(/defaultPresenterFactory\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
|
|
50
|
-
} else if (/defaultPresenter\s*:/.test(nextContent)) {
|
|
51
|
-
nextContent = nextContent.replace(/defaultPresenter\s*:\s*(\{[\s\S]*?\n\s*\}|['"`][^'"`]+['"`])/m, defaultFactoryEntry);
|
|
52
|
-
} else {
|
|
53
|
-
nextContent = nextContent.replace(/export\s+default\s*\{([\s\S]*)\}\s*;?/, (_full, body: string) => {
|
|
54
|
-
const trimmedRight = body.replace(/\s*$/, '');
|
|
55
|
-
if (!trimmedRight.length) {
|
|
56
|
-
return `export default {\n\t${defaultFactoryEntry}\n};`;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
|
|
60
|
-
return `export default {${withComma}\n\t${defaultFactoryEntry}\n};`;
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
return nextContent;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
export default async function createPresenterFactory(): Promise<void> {
|
|
67
|
-
const { presenterFactoryNameRaw } = await prompts({
|
|
68
|
-
type: 'text',
|
|
69
|
-
name: 'presenterFactoryNameRaw',
|
|
70
|
-
message: 'Presenter factory name:',
|
|
71
|
-
initial: 'AppPresenter'
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
const presenterFactoryName = toPascalCase(String(presenterFactoryNameRaw ?? 'AppPresenter')) || 'AppPresenter';
|
|
75
|
-
const { sharedContext } = await getSharedState();
|
|
76
|
-
const presenterRootPath = getFoundationConstructPath(sharedContext.name, 'presenter');
|
|
77
|
-
const filePath = path.join(presenterRootPath, `${presenterFactoryName}.ts`);
|
|
78
|
-
|
|
79
|
-
await fs.mkdir(presenterRootPath, { recursive: true });
|
|
80
|
-
|
|
81
|
-
const created = await writeIfNotExists(filePath, createPresenterFactoryTemplate(presenterFactoryName));
|
|
82
|
-
if (!created) {
|
|
83
|
-
console.log(`⚠️ Presenter factory "${presenterFactoryName}" already exists. File was not overwritten.`);
|
|
84
|
-
} else {
|
|
85
|
-
await updateIndexTs(presenterRootPath);
|
|
86
|
-
console.log(`✅ Presenter factory created: ${filePath}`);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const { useAsDefault } = await prompts({
|
|
90
|
-
type: 'confirm',
|
|
91
|
-
name: 'useAsDefault',
|
|
92
|
-
message: 'Use this presenter factory as default for the project?',
|
|
93
|
-
initial: true
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
if (!useAsDefault) return;
|
|
97
|
-
|
|
98
|
-
const config = resolveConfigFile(process.cwd());
|
|
99
|
-
const nextContent = upsertDefaultPresenterFactoryConfig(config.content, presenterFactoryName);
|
|
100
|
-
await fs.writeFile(config.filepath, nextContent, 'utf-8');
|
|
101
|
-
console.log(`✅ Default presenter factory saved to ${path.basename(config.filepath)}`);
|
|
102
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { writeIfNotExists } from '../utils/fileUtils.js';
|
|
3
|
-
|
|
4
|
-
const createProgramTemplate = (): string => `import { createApp } from '@azure-net/kit';
|
|
5
|
-
|
|
6
|
-
export const { register, Container } = createApp((app) => app);
|
|
7
|
-
`;
|
|
8
|
-
|
|
9
|
-
export default async function createProgram(): Promise<void> {
|
|
10
|
-
const programPath = path.join(process.cwd(), 'src', 'program.ts');
|
|
11
|
-
const created = await writeIfNotExists(programPath, createProgramTemplate());
|
|
12
|
-
|
|
13
|
-
if (!created) {
|
|
14
|
-
console.log('⚠️ Program already exists. Nothing was overwritten.');
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
console.log(`✅ Program created: ${programPath}`);
|
|
19
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import prompts from 'prompts';
|
|
4
|
-
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
5
|
-
import { toPascalCase } from '../utils/contextUtils.js';
|
|
6
|
-
import { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
7
|
-
|
|
8
|
-
const createResponseWithWrapperTemplate = (name: string): string => {
|
|
9
|
-
const interfaceName = `I${name}`;
|
|
10
|
-
return `import { ResponseBuilder } from '@azure-net/kit/infra';
|
|
11
|
-
|
|
12
|
-
export interface ${interfaceName}<T> {
|
|
13
|
-
\tdata: T;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export class ${name}<TData = unknown, TMeta = unknown> extends ResponseBuilder<TData, TMeta, ${interfaceName}<TData>> {
|
|
17
|
-
\tprotected unwrapData(data: ${interfaceName}<TData>): TData {
|
|
18
|
-
\t\treturn data.data;
|
|
19
|
-
\t}
|
|
20
|
-
}
|
|
21
|
-
`;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const createResponseSimpleTemplate = (name: string): string => `import { ResponseBuilder } from '@azure-net/kit/infra';
|
|
25
|
-
|
|
26
|
-
export class ${name}<TData = unknown, TMeta = unknown> extends ResponseBuilder<TData, TMeta> {}
|
|
27
|
-
`;
|
|
28
|
-
|
|
29
|
-
const ensureResponseName = (rawName: string): string => {
|
|
30
|
-
const normalized = toPascalCase(rawName || 'ApiResponse') || 'ApiResponse';
|
|
31
|
-
return normalized.endsWith('Response') ? normalized : `${normalized}Response`;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export default async function createResponse(): Promise<void> {
|
|
35
|
-
const { responseNameRaw } = await prompts({
|
|
36
|
-
type: 'text',
|
|
37
|
-
name: 'responseNameRaw',
|
|
38
|
-
message: 'Response class name:',
|
|
39
|
-
initial: 'ApiResponse'
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
const responseName = ensureResponseName(String(responseNameRaw ?? 'ApiResponse'));
|
|
43
|
-
|
|
44
|
-
const { useCommonResponseWrapper } = await prompts({
|
|
45
|
-
type: 'confirm',
|
|
46
|
-
name: 'useCommonResponseWrapper',
|
|
47
|
-
message: 'Use common backend response wrapper interface?',
|
|
48
|
-
initial: true
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const { sharedContext } = await getSharedState();
|
|
52
|
-
const responseRoot = getFoundationConstructPath(sharedContext.name, 'response');
|
|
53
|
-
const filePath = path.join(responseRoot, `${responseName}.ts`);
|
|
54
|
-
await fs.mkdir(responseRoot, { recursive: true });
|
|
55
|
-
|
|
56
|
-
const template = useCommonResponseWrapper ? createResponseWithWrapperTemplate(responseName) : createResponseSimpleTemplate(responseName);
|
|
57
|
-
const created = await writeIfNotExists(filePath, template);
|
|
58
|
-
await updateIndexTs(responseRoot);
|
|
59
|
-
|
|
60
|
-
if (!created) {
|
|
61
|
-
console.log(`⚠️ Response "${responseName}" already exists. File was not overwritten.`);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
console.log(`✅ Response created: ${filePath}`);
|
|
66
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import prompts from 'prompts';
|
|
4
|
-
import { writeIfNotExists, updateIndexTs } from '../utils/fileUtils.js';
|
|
5
|
-
import { toPascalCase, toCamelCase } from '../utils/contextUtils.js';
|
|
6
|
-
import { getFoundationConstructPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
7
|
-
|
|
8
|
-
const createSchemaRuleTemplate = (
|
|
9
|
-
ruleName: string
|
|
10
|
-
): string => `import type { ValidationParams, ValidationRuleResult } from '@azure-net/kit/delivery';
|
|
11
|
-
|
|
12
|
-
export const ${ruleName} = <T = unknown, D = unknown>(): ValidationRuleResult<T, D> => {
|
|
13
|
-
\treturn (validationParams: ValidationParams<T, D>) => {
|
|
14
|
-
\t\treturn undefined;
|
|
15
|
-
\t};
|
|
16
|
-
};
|
|
17
|
-
`;
|
|
18
|
-
|
|
19
|
-
export default async function createSchemaRule(): Promise<void> {
|
|
20
|
-
const { ruleNameRaw } = await prompts({
|
|
21
|
-
type: 'text',
|
|
22
|
-
name: 'ruleNameRaw',
|
|
23
|
-
message: 'Schema rule name:',
|
|
24
|
-
initial: 'File'
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const pascalName = toPascalCase(String(ruleNameRaw ?? 'File')) || 'File';
|
|
28
|
-
const camelName = toCamelCase(pascalName) || 'file';
|
|
29
|
-
const { sharedContext } = await getSharedState();
|
|
30
|
-
const rulesPath = path.join(getFoundationConstructPath(sharedContext.name, 'schema'), 'custom-rules');
|
|
31
|
-
const filePath = path.join(rulesPath, `${pascalName}.ts`);
|
|
32
|
-
|
|
33
|
-
await fs.mkdir(rulesPath, { recursive: true });
|
|
34
|
-
|
|
35
|
-
const created = await writeIfNotExists(filePath, createSchemaRuleTemplate(camelName));
|
|
36
|
-
await updateIndexTs(rulesPath);
|
|
37
|
-
|
|
38
|
-
if (!created) {
|
|
39
|
-
console.log(`⚠️ Schema rule "${pascalName}" already exists. File was not overwritten.`);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
console.log(`✅ Schema rule created: ${filePath}`);
|
|
44
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import prompts from 'prompts';
|
|
4
|
-
import { writeIfNotExists } from '../utils/fileUtils.js';
|
|
5
|
-
import { getLocalizationPath, getSharedState } from '../utils/sharedFoundation.js';
|
|
6
|
-
|
|
7
|
-
const parseLocales = (rawLocales: string): string[] => {
|
|
8
|
-
const parsed = String(rawLocales ?? '')
|
|
9
|
-
.split(',')
|
|
10
|
-
.map((item) => item.trim().toLowerCase())
|
|
11
|
-
.filter(Boolean);
|
|
12
|
-
|
|
13
|
-
const unique = Array.from(new Set(parsed));
|
|
14
|
-
return unique.length ? unique : ['en', 'ru'];
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
const createTranslationIndexTemplate = (defaultLocale: string): string => `import { messages } from './locales/index.js';
|
|
18
|
-
import { createTranslations, type Path } from '@azure-net/kit/i18n';
|
|
19
|
-
|
|
20
|
-
export const TranslationManager = createTranslations({
|
|
21
|
-
\tmessages,
|
|
22
|
-
\tinitLang: '${defaultLocale}',
|
|
23
|
-
\tinitLangFromAcceptLanguage: true,
|
|
24
|
-
\tcookieName: 'current-language'
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
type MessagesList = Awaited<ReturnType<(typeof messages)[keyof typeof messages]>>;
|
|
28
|
-
type TranslationExtended = { key: MessageKeys | string; vars?: Record<string, unknown> };
|
|
29
|
-
|
|
30
|
-
export type MessageKeys = Path<MessagesList>;
|
|
31
|
-
export type TranslationParam = MessageKeys | string | TranslationExtended;
|
|
32
|
-
export type AvailableLocales = keyof typeof messages;
|
|
33
|
-
`;
|
|
34
|
-
|
|
35
|
-
const createLocalesIndexTemplate = (locales: string[]): string => {
|
|
36
|
-
const lines = locales.map((locale) => `\t${locale}: () => import('./${locale}/index.js').then((res) => res.default)`);
|
|
37
|
-
return `export const messages = {\n${lines.join(',\n')}\n};\n`;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const createLocaleTemplate = (): string => `export default {
|
|
41
|
-
\ttest: 'test'
|
|
42
|
-
};
|
|
43
|
-
`;
|
|
44
|
-
|
|
45
|
-
export default async function createTranslationManager(): Promise<void> {
|
|
46
|
-
const { localesRaw } = await prompts({
|
|
47
|
-
type: 'text',
|
|
48
|
-
name: 'localesRaw',
|
|
49
|
-
message: 'Enter locales (comma separated):',
|
|
50
|
-
initial: 'en, ru'
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const locales = parseLocales(String(localesRaw ?? 'en, ru'));
|
|
54
|
-
|
|
55
|
-
const { defaultLocale } = await prompts({
|
|
56
|
-
type: 'select',
|
|
57
|
-
name: 'defaultLocale',
|
|
58
|
-
message: 'Choose default locale:',
|
|
59
|
-
choices: locales.map((locale) => ({ title: locale, value: locale })),
|
|
60
|
-
initial: 0
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
const selectedDefaultLocale = String(defaultLocale ?? locales[0] ?? 'en');
|
|
64
|
-
|
|
65
|
-
const { sharedContext } = await getSharedState();
|
|
66
|
-
const translationRoot = getLocalizationPath(sharedContext.name);
|
|
67
|
-
const localesRoot = path.join(translationRoot, 'locales');
|
|
68
|
-
await fs.mkdir(localesRoot, { recursive: true });
|
|
69
|
-
|
|
70
|
-
await writeIfNotExists(path.join(translationRoot, 'index.ts'), createTranslationIndexTemplate(selectedDefaultLocale));
|
|
71
|
-
await writeIfNotExists(path.join(localesRoot, 'index.ts'), createLocalesIndexTemplate(locales));
|
|
72
|
-
|
|
73
|
-
for (const locale of locales) {
|
|
74
|
-
const localeDir = path.join(localesRoot, locale);
|
|
75
|
-
await fs.mkdir(localeDir, { recursive: true });
|
|
76
|
-
await writeIfNotExists(path.join(localeDir, 'index.ts'), createLocaleTemplate());
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
console.log(`✅ Translation manager created: ${translationRoot}`);
|
|
80
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import prompts from 'prompts';
|
|
4
|
-
import { loadUserConfig } from './loadConfig.js';
|
|
5
|
-
|
|
6
|
-
const APP_PATH = path.join(process.cwd(), 'src/app');
|
|
7
|
-
|
|
8
|
-
function normalizeContextNames(rawContexts: unknown): string[] {
|
|
9
|
-
if (!Array.isArray(rawContexts)) return [];
|
|
10
|
-
|
|
11
|
-
return rawContexts
|
|
12
|
-
.map((item) => {
|
|
13
|
-
if (typeof item === 'string') {
|
|
14
|
-
return item.trim();
|
|
15
|
-
}
|
|
16
|
-
if (!item || typeof item !== 'object') return '';
|
|
17
|
-
return String(item.name ?? '').trim();
|
|
18
|
-
})
|
|
19
|
-
.filter(Boolean);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export async function selectContext(message = 'Select context:'): Promise<string | null> {
|
|
23
|
-
const config = await loadUserConfig();
|
|
24
|
-
const contexts = normalizeContextNames(config.contexts);
|
|
25
|
-
|
|
26
|
-
const { context } = await prompts({
|
|
27
|
-
type: 'select',
|
|
28
|
-
name: 'context',
|
|
29
|
-
message,
|
|
30
|
-
choices: contexts.map((c) => ({ title: c, value: c }))
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
return context ? String(context) : null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function getContextPath(context: string): string {
|
|
37
|
-
return path.join(APP_PATH, context, 'layers');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export async function getAvailableFiles(dir: string, pattern = '.ts'): Promise<string[]> {
|
|
41
|
-
try {
|
|
42
|
-
const files = await fs.readdir(dir);
|
|
43
|
-
return files.filter((f) => f.endsWith(pattern) && f !== 'index.ts').map((f) => f.replace(pattern, ''));
|
|
44
|
-
} catch {
|
|
45
|
-
return [];
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export async function getApplicationProviderServices(context: string): Promise<string[]> {
|
|
50
|
-
const contextPath = getContextPath(context);
|
|
51
|
-
const providerPath = path.join(contextPath, 'application/providers/ApplicationProvider.ts');
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
const content = await fs.readFile(providerPath, 'utf-8');
|
|
55
|
-
// Extract service names from ApplicationProvider
|
|
56
|
-
const serviceRegex = /(\w+Service):\s*\(/g;
|
|
57
|
-
const services: string[] = [];
|
|
58
|
-
let match;
|
|
59
|
-
|
|
60
|
-
while ((match = serviceRegex.exec(content)) !== null) {
|
|
61
|
-
const serviceName = match[1];
|
|
62
|
-
if (serviceName) services.push(serviceName);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return services;
|
|
66
|
-
} catch {
|
|
67
|
-
return [];
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function toPascalCase(str: string): string {
|
|
72
|
-
return str
|
|
73
|
-
.split(/[-_\s]+/)
|
|
74
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
75
|
-
.join('');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export function toCamelCase(str: string): string {
|
|
79
|
-
const pascal = toPascalCase(str);
|
|
80
|
-
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function toKebabCase(str: string): string {
|
|
84
|
-
return str
|
|
85
|
-
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
86
|
-
.replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
|
|
87
|
-
.toLowerCase();
|
|
88
|
-
}
|
package/src/utils/fileUtils.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import fs from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
export async function writeIfNotExists(filepath: string, content: string): Promise<boolean> {
|
|
5
|
-
try {
|
|
6
|
-
await fs.access(filepath);
|
|
7
|
-
console.log(`⚠️ Skip existing: ${filepath}`);
|
|
8
|
-
return false;
|
|
9
|
-
} catch {
|
|
10
|
-
await fs.mkdir(path.dirname(filepath), { recursive: true });
|
|
11
|
-
await fs.writeFile(filepath, content, 'utf-8');
|
|
12
|
-
console.log(`✅ Created: ${filepath}`);
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function updateIndexTs(dir: string, filePattern = '.ts', ignore: string[] = ['index.ts']): Promise<void> {
|
|
18
|
-
try {
|
|
19
|
-
const files = (await fs.readdir(dir)).filter((f) => f.endsWith(filePattern) && !ignore.includes(f));
|
|
20
|
-
const content = files.map((f) => `export * from './${f.replace('.ts', '')}';`).join('\n') + '\n';
|
|
21
|
-
await fs.writeFile(path.join(dir, 'index.ts'), content, 'utf-8');
|
|
22
|
-
} catch {
|
|
23
|
-
// Directory doesn't exist yet
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export async function ensureIndexExports(layerPath: string): Promise<void> {
|
|
28
|
-
try {
|
|
29
|
-
const subdirs = await fs.readdir(layerPath, { withFileTypes: true });
|
|
30
|
-
const exportLines = subdirs.filter((d) => d.isDirectory()).map((d) => `export * from './${d.name}';`);
|
|
31
|
-
|
|
32
|
-
if (exportLines.length > 0) {
|
|
33
|
-
await fs.writeFile(path.join(layerPath, 'index.ts'), exportLines.join('\n') + '\n', 'utf-8');
|
|
34
|
-
}
|
|
35
|
-
} catch {
|
|
36
|
-
// Directory doesn't exist
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export async function injectIntoFile(
|
|
41
|
-
filepath: string,
|
|
42
|
-
searchPattern: string,
|
|
43
|
-
newContent: string,
|
|
44
|
-
position: 'after' | 'before' = 'after'
|
|
45
|
-
): Promise<boolean> {
|
|
46
|
-
try {
|
|
47
|
-
let content = await fs.readFile(filepath, 'utf-8');
|
|
48
|
-
const index = content.indexOf(searchPattern);
|
|
49
|
-
|
|
50
|
-
if (index === -1) {
|
|
51
|
-
console.warn(`Pattern not found in ${filepath}`);
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (content.includes(newContent.trim())) {
|
|
56
|
-
console.log(`Content already exists in ${filepath}`);
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (position === 'after') {
|
|
61
|
-
const insertIndex = index + searchPattern.length;
|
|
62
|
-
content = content.slice(0, insertIndex) + '\n' + newContent + content.slice(insertIndex);
|
|
63
|
-
} else {
|
|
64
|
-
content = content.slice(0, index) + newContent + '\n' + content.slice(index);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
await fs.writeFile(filepath, content, 'utf-8');
|
|
68
|
-
console.log(`✅ Updated: ${filepath}`);
|
|
69
|
-
return true;
|
|
70
|
-
} catch (error: unknown) {
|
|
71
|
-
console.error(`Failed to update ${filepath}:`, error instanceof Error ? error.message : String(error));
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
}
|
package/src/utils/loadConfig.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import fsSync from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
|
|
5
|
-
export type AzureNetConfig = {
|
|
6
|
-
contexts: Array<string | { name?: string; alias?: string }>;
|
|
7
|
-
defaultContext: string;
|
|
8
|
-
sharedAlias?: string;
|
|
9
|
-
packageManager?: string;
|
|
10
|
-
defaultSchemaFactory?: string;
|
|
11
|
-
defaultPresenterFactory?: string;
|
|
12
|
-
groupRoutesFunc?: unknown;
|
|
13
|
-
[key: string]: unknown;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const DEFAULT_CONFIG: AzureNetConfig = {
|
|
17
|
-
contexts: [],
|
|
18
|
-
defaultContext: 'web'
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
function toObjectFromDefaultExport(content: string): Record<string, unknown> {
|
|
22
|
-
const source = String(content ?? '').trim();
|
|
23
|
-
if (!source.length) return {};
|
|
24
|
-
|
|
25
|
-
const replacedExport = source.replace(/^\s*export\s+default\s+/m, 'return ');
|
|
26
|
-
if (replacedExport === source) return {};
|
|
27
|
-
|
|
28
|
-
const withSemicolon = /;\s*$/.test(replacedExport) ? replacedExport : `${replacedExport};`;
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
return new Function(withSemicolon)() ?? {};
|
|
32
|
-
} catch {
|
|
33
|
-
return {};
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function resolveConfigFile(cwd = process.cwd()): { exists: boolean; filepath: string; type: 'ts' | 'js' } {
|
|
38
|
-
const tsPath = path.join(cwd, 'azure-net.config.ts');
|
|
39
|
-
const jsPath = path.join(cwd, 'azure-net.config.js');
|
|
40
|
-
|
|
41
|
-
if (fsSync.existsSync(tsPath)) {
|
|
42
|
-
return { exists: true, filepath: tsPath, type: 'ts' };
|
|
43
|
-
}
|
|
44
|
-
if (fsSync.existsSync(jsPath)) {
|
|
45
|
-
return { exists: true, filepath: jsPath, type: 'js' };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return { exists: false, filepath: tsPath, type: 'ts' };
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export async function loadUserConfig(): Promise<AzureNetConfig> {
|
|
52
|
-
const { exists, filepath } = resolveConfigFile();
|
|
53
|
-
if (!exists) {
|
|
54
|
-
return { ...DEFAULT_CONFIG };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
const content = await fs.readFile(filepath, 'utf-8');
|
|
59
|
-
const parsed = toObjectFromDefaultExport(content);
|
|
60
|
-
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
61
|
-
return { ...DEFAULT_CONFIG };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return { ...DEFAULT_CONFIG, ...(parsed as Record<string, unknown>) };
|
|
65
|
-
} catch {
|
|
66
|
-
return { ...DEFAULT_CONFIG };
|
|
67
|
-
}
|
|
68
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { normalizeContexts } from '../init/initAliases.js';
|
|
3
|
-
import { loadUserConfig, resolveConfigFile } from './loadConfig.js';
|
|
4
|
-
|
|
5
|
-
export type FoundationConstruct = 'datasource' | 'presenter' | 'provider' | 'response' | 'schema';
|
|
6
|
-
export type ContextConfig = { name: string; alias: string };
|
|
7
|
-
|
|
8
|
-
export const SHARED_ESSENTIALS_DIR_NAME = 'essentials';
|
|
9
|
-
|
|
10
|
-
const normalizeAlias = (value: unknown): string => {
|
|
11
|
-
const raw = String(value ?? '').trim();
|
|
12
|
-
return raw.startsWith('$') ? raw : `$${raw}`;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const createMissingSharedAliasError = (): Error =>
|
|
16
|
-
new Error(
|
|
17
|
-
'`sharedAlias` is missing in azure-net.config.ts/js. Add sharedAlias and make sure it points to one of `contexts`, for example: sharedAlias: "$shared-kernel".'
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
export const getSharedState = async (): Promise<{ contexts: ContextConfig[]; sharedAlias: string; sharedContext: ContextConfig }> => {
|
|
21
|
-
const config = await loadUserConfig();
|
|
22
|
-
const contexts = normalizeContexts(config.contexts) as ContextConfig[];
|
|
23
|
-
const sharedAliasRaw = String(config.sharedAlias ?? '').trim();
|
|
24
|
-
|
|
25
|
-
if (!sharedAliasRaw.length) throw createMissingSharedAliasError();
|
|
26
|
-
|
|
27
|
-
const sharedAlias = normalizeAlias(sharedAliasRaw);
|
|
28
|
-
const sharedContext = contexts.find((context) => normalizeAlias(context.alias) === sharedAlias);
|
|
29
|
-
|
|
30
|
-
if (!sharedContext) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
`sharedAlias "${sharedAlias}" does not point to any configured context. Add a context with alias "${sharedAlias}" in azure-net.config.ts/js.`
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
contexts,
|
|
38
|
-
sharedAlias,
|
|
39
|
-
sharedContext
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export const hasSharedAliasConfig = async (): Promise<boolean> => {
|
|
44
|
-
const config = await loadUserConfig();
|
|
45
|
-
return String(config.sharedAlias ?? '').trim().length > 0;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export const getSharedContextRootPath = (sharedContextName: string): string => path.join(process.cwd(), 'src', 'app', sharedContextName);
|
|
49
|
-
|
|
50
|
-
export const getSharedEssentialsPath = (sharedContextName: string): string =>
|
|
51
|
-
path.join(getSharedContextRootPath(sharedContextName), SHARED_ESSENTIALS_DIR_NAME);
|
|
52
|
-
|
|
53
|
-
export const getFoundationRootPath = (sharedContextName: string): string =>
|
|
54
|
-
path.join(getSharedEssentialsPath(sharedContextName), 'foundation', 'constructs');
|
|
55
|
-
|
|
56
|
-
export const getFoundationConstructPath = (sharedContextName: string, construct: FoundationConstruct): string =>
|
|
57
|
-
path.join(getFoundationRootPath(sharedContextName), construct);
|
|
58
|
-
|
|
59
|
-
export const getFoundationConstructImportPath = (sharedAlias: string, construct: FoundationConstruct): string =>
|
|
60
|
-
`${sharedAlias}/${SHARED_ESSENTIALS_DIR_NAME}/foundation/constructs/${construct}`;
|
|
61
|
-
|
|
62
|
-
export const getLocalizationPath = (sharedContextName: string): string =>
|
|
63
|
-
path.join(getSharedEssentialsPath(sharedContextName), 'localization');
|
|
64
|
-
|
|
65
|
-
export const getLocalizationImportPath = (sharedAlias: string): string => `${sharedAlias}/${SHARED_ESSENTIALS_DIR_NAME}/localization`;
|
|
66
|
-
|
|
67
|
-
export const getConfigFileLabel = (): string => {
|
|
68
|
-
const config = resolveConfigFile();
|
|
69
|
-
return config.exists ? path.basename(config.filepath) : 'azure-net.config.ts/js';
|
|
70
|
-
};
|
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"rootDir": ".",
|
|
7
|
-
"outDir": "dist",
|
|
8
|
-
"allowJs": true,
|
|
9
|
-
"checkJs": false,
|
|
10
|
-
"declaration": true,
|
|
11
|
-
"sourceMap": true,
|
|
12
|
-
"strict": true,
|
|
13
|
-
"noUncheckedIndexedAccess": true,
|
|
14
|
-
"esModuleInterop": true,
|
|
15
|
-
"skipLibCheck": true
|
|
16
|
-
},
|
|
17
|
-
"include": ["bin/**/*.ts", "src/**/*"],
|
|
18
|
-
"exclude": ["dist", "node_modules"]
|
|
19
|
-
}
|
|
File without changes
|
|
File without changes
|