@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
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { format } from 'prettier';
|
|
4
|
+
export const PACKAGE_IMPORTS = Object.fromEntries(['Contexts', 'Presentation', 'Platform'].flatMap((name) => {
|
|
5
|
+
const key = '#' + name.toLowerCase(), root = './src/app/' + name;
|
|
6
|
+
return [
|
|
7
|
+
[key, root + '/index.ts'],
|
|
8
|
+
[key + '/*', { types: [root + '/*.ts', root + '/*/index.ts', root + '/*'], default: root + '/*' }]
|
|
9
|
+
];
|
|
10
|
+
}));
|
|
11
|
+
export async function mergePackageImports(content) {
|
|
12
|
+
const json = JSON.parse(content);
|
|
13
|
+
if (!json || typeof json !== 'object' || Array.isArray(json))
|
|
14
|
+
throw new Error('Expected a package.json object');
|
|
15
|
+
if (json.imports !== undefined && (!json.imports || typeof json.imports !== 'object' || Array.isArray(json.imports)))
|
|
16
|
+
throw new Error('Expected package.json imports object');
|
|
17
|
+
const imports = { ...json.imports };
|
|
18
|
+
for (const [key, value] of Object.entries(PACKAGE_IMPORTS)) {
|
|
19
|
+
if (key in imports && JSON.stringify(imports[key]) !== JSON.stringify(value))
|
|
20
|
+
throw new Error(`Conflicting package import ${key}; review its target before initialization.`);
|
|
21
|
+
imports[key] = value;
|
|
22
|
+
}
|
|
23
|
+
return format(JSON.stringify({ ...json, imports }), { parser: 'json', useTabs: true });
|
|
24
|
+
}
|
|
25
|
+
export async function initializePackageImports() {
|
|
26
|
+
const file = path.resolve('package.json');
|
|
27
|
+
let content;
|
|
28
|
+
try {
|
|
29
|
+
content = await fs.readFile(file, 'utf8');
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (error.code !== 'ENOENT')
|
|
33
|
+
throw error;
|
|
34
|
+
content = '{}';
|
|
35
|
+
}
|
|
36
|
+
await fs.writeFile(file, await mergePackageImports(content));
|
|
37
|
+
}
|
|
38
|
+
export function resolvePackageImport(imports, specifier, root) {
|
|
39
|
+
const target = (v) => {
|
|
40
|
+
if (typeof v === 'string')
|
|
41
|
+
return v;
|
|
42
|
+
if (Array.isArray(v))
|
|
43
|
+
return v.map(target).find(Boolean);
|
|
44
|
+
if (v && typeof v === 'object') {
|
|
45
|
+
const obj = v;
|
|
46
|
+
return target(obj.default ?? obj.import ?? obj.types);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
for (const key of Object.keys(imports).sort((a, b) => b.replace('*', '').length - a.replace('*', '').length)) {
|
|
50
|
+
const value = target(imports[key]);
|
|
51
|
+
if (!value?.startsWith('./'))
|
|
52
|
+
continue;
|
|
53
|
+
if (!key.includes('*')) {
|
|
54
|
+
if (key === specifier)
|
|
55
|
+
return path.resolve(root, value);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const [prefix, suffix = ''] = key.split('*');
|
|
59
|
+
if (specifier.startsWith(prefix) && specifier.endsWith(suffix))
|
|
60
|
+
return path.resolve(root, value.replace('*', specifier.slice(prefix.length, suffix ? -suffix.length : undefined)));
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
@@ -1,48 +1,42 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
export const SHARED_ESSENTIALS_DIR_NAME = '
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { discoverContexts, getContextPath, getPlatformPath, SHARED_CONTEXT } from './architecture.js';
|
|
3
|
+
import { resolveConfigFile } from './loadConfig.js';
|
|
4
|
+
export const SHARED_ESSENTIALS_DIR_NAME = 'Platform';
|
|
5
|
+
const constructNames = {
|
|
6
|
+
datasource: 'Datasource',
|
|
7
|
+
presenter: 'Presenter',
|
|
8
|
+
provider: 'DI',
|
|
9
|
+
response: 'Response',
|
|
10
|
+
schema: 'Schema'
|
|
8
11
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
throw new Error(
|
|
22
|
-
`sharedAlias "${sharedAlias}" does not point to any configured context. Add a context with alias "${sharedAlias}" in azure-net.config.ts/js.`
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
return {
|
|
26
|
-
contexts,
|
|
27
|
-
sharedAlias,
|
|
28
|
-
sharedContext
|
|
29
|
-
};
|
|
12
|
+
export async function getSharedState() {
|
|
13
|
+
const names = await discoverContexts();
|
|
14
|
+
if (!names.includes(SHARED_CONTEXT))
|
|
15
|
+
names.push(SHARED_CONTEXT);
|
|
16
|
+
const contexts = names.sort().map((name) => ({ name, alias: `#contexts/${name}` }));
|
|
17
|
+
return { contexts, sharedAlias: '#platform', sharedContext: contexts.find((context) => context.name === SHARED_CONTEXT) };
|
|
18
|
+
}
|
|
19
|
+
export const hasSharedAliasConfig = async () => true;
|
|
20
|
+
export const getSharedContextRootPath = (name = SHARED_CONTEXT) => getContextPath(name);
|
|
21
|
+
export const getSharedEssentialsPath = (...compatibility) => {
|
|
22
|
+
void compatibility;
|
|
23
|
+
return getPlatformPath();
|
|
30
24
|
};
|
|
31
|
-
export const
|
|
32
|
-
|
|
33
|
-
|
|
25
|
+
export const getFoundationRootPath = (...compatibility) => {
|
|
26
|
+
void compatibility;
|
|
27
|
+
return path.join(getPlatformPath(), 'Foundation');
|
|
28
|
+
};
|
|
29
|
+
export const getFoundationConstructPath = (name, construct) => path.join(getFoundationRootPath(name), constructNames[construct]);
|
|
30
|
+
export const getFoundationConstructImportPath = (_alias, construct) => `#platform/Foundation/${constructNames[construct]}`;
|
|
31
|
+
export const getLocalizationPath = (...compatibility) => {
|
|
32
|
+
void compatibility;
|
|
33
|
+
return path.join(getPlatformPath(), 'Bootstrap', 'Localization');
|
|
34
|
+
};
|
|
35
|
+
export const getLocalizationImportPath = (...compatibility) => {
|
|
36
|
+
void compatibility;
|
|
37
|
+
return '#platform/Bootstrap/Localization';
|
|
34
38
|
};
|
|
35
|
-
export const getSharedContextRootPath = (sharedContextName) => path.join(process.cwd(), 'src', 'app', sharedContextName);
|
|
36
|
-
export const getSharedEssentialsPath = (sharedContextName) =>
|
|
37
|
-
path.join(getSharedContextRootPath(sharedContextName), SHARED_ESSENTIALS_DIR_NAME);
|
|
38
|
-
export const getFoundationRootPath = (sharedContextName) =>
|
|
39
|
-
path.join(getSharedEssentialsPath(sharedContextName), 'foundation', 'constructs');
|
|
40
|
-
export const getFoundationConstructPath = (sharedContextName, construct) => path.join(getFoundationRootPath(sharedContextName), construct);
|
|
41
|
-
export const getFoundationConstructImportPath = (sharedAlias, construct) =>
|
|
42
|
-
`${sharedAlias}/${SHARED_ESSENTIALS_DIR_NAME}/foundation/constructs/${construct}`;
|
|
43
|
-
export const getLocalizationPath = (sharedContextName) => path.join(getSharedEssentialsPath(sharedContextName), 'localization');
|
|
44
|
-
export const getLocalizationImportPath = (sharedAlias) => `${sharedAlias}/${SHARED_ESSENTIALS_DIR_NAME}/localization`;
|
|
45
39
|
export const getConfigFileLabel = () => {
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
const config = resolveConfigFile();
|
|
41
|
+
return config.exists ? path.basename(config.filepath) : 'azure-net.config.ts/js';
|
|
48
42
|
};
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import ts from 'typescript';
|
|
4
|
+
import { format, resolveConfig } from 'prettier';
|
|
5
|
+
import { mergeAliasesInSvelteConfig } from './legacyAliases.js';
|
|
6
|
+
import { ARCHITECTURE_ALIASES } from './architecture.js';
|
|
7
|
+
export const VITE_CONFIGS = ['vite.config.ts', 'vite.config.js', 'vite.config.mts', 'vite.config.mjs'];
|
|
8
|
+
export const SVELTE_CONFIGS = ['svelte.config.js', 'svelte.config.ts', 'svelte.config.mjs'];
|
|
9
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
10
|
+
const parse = (text) => ts.createSourceFile('config.ts', text, ts.ScriptTarget.Latest, true);
|
|
11
|
+
const name = (node) => node && (ts.isIdentifier(node) || ts.isStringLiteral(node)) ? node.text : undefined;
|
|
12
|
+
function object(expression, source, seen = new Set()) {
|
|
13
|
+
if (ts.isObjectLiteralExpression(expression))
|
|
14
|
+
return expression;
|
|
15
|
+
if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isSatisfiesExpression(expression))
|
|
16
|
+
return object(expression.expression, source, seen);
|
|
17
|
+
if (ts.isIdentifier(expression) && !seen.has(expression.text)) {
|
|
18
|
+
seen.add(expression.text);
|
|
19
|
+
for (const statement of source.statements)
|
|
20
|
+
if (ts.isVariableStatement(statement))
|
|
21
|
+
for (const d of statement.declarationList.declarations)
|
|
22
|
+
if (name(d.name) === expression.text && d.initializer)
|
|
23
|
+
return object(d.initializer, source, seen);
|
|
24
|
+
}
|
|
25
|
+
throw new Error('Cannot safely edit dynamic SvelteKit options. Use an object literal or a local object variable in sveltekit().');
|
|
26
|
+
}
|
|
27
|
+
function kitCall(source) {
|
|
28
|
+
const names = new Set();
|
|
29
|
+
for (const s of source.statements)
|
|
30
|
+
if (ts.isImportDeclaration(s) && ts.isStringLiteral(s.moduleSpecifier) && s.moduleSpecifier.text === '@sveltejs/kit/vite') {
|
|
31
|
+
const b = s.importClause?.namedBindings;
|
|
32
|
+
if (b && ts.isNamedImports(b))
|
|
33
|
+
for (const e of b.elements)
|
|
34
|
+
if ((e.propertyName?.text ?? e.name.text) === 'sveltekit')
|
|
35
|
+
names.add(e.name.text);
|
|
36
|
+
}
|
|
37
|
+
const calls = [];
|
|
38
|
+
const visit = (n) => {
|
|
39
|
+
if (ts.isCallExpression(n) && ts.isIdentifier(n.expression) && names.has(n.expression.text))
|
|
40
|
+
calls.push(n);
|
|
41
|
+
ts.forEachChild(n, visit);
|
|
42
|
+
};
|
|
43
|
+
visit(source);
|
|
44
|
+
if (calls.length !== 1)
|
|
45
|
+
throw new Error('Expected exactly one imported sveltekit() call in vite.config. No files changed.');
|
|
46
|
+
return calls[0];
|
|
47
|
+
}
|
|
48
|
+
function modernOptions(input, source) {
|
|
49
|
+
const has = (obj, key) => obj.properties.some((p) => name(p.name) === key);
|
|
50
|
+
const nestedHas = (key, keys) => {
|
|
51
|
+
const property = input.properties.find((p) => name(p.name) === key);
|
|
52
|
+
if (!property || !ts.isPropertyAssignment(property))
|
|
53
|
+
return false;
|
|
54
|
+
const value = objectOrUndefined(property.initializer, source);
|
|
55
|
+
return value && keys.some((k) => has(value, k));
|
|
56
|
+
};
|
|
57
|
+
if (!['kit', 'vitePlugin', 'preloadStrategy'].some((k) => has(input, k)) &&
|
|
58
|
+
!nestedHas('files', ['lib']) &&
|
|
59
|
+
!nestedHas('experimental', ['handleRenderingErrors', 'instrumentation', 'tracing']) &&
|
|
60
|
+
!nestedHas('prerender', ['origin']) &&
|
|
61
|
+
!nestedHas('csrf', ['checkOrigin']))
|
|
62
|
+
return input.getText(source);
|
|
63
|
+
const print = (n) => printer.printNode(ts.EmitHint.Unspecified, n, source);
|
|
64
|
+
const props = [...input.properties];
|
|
65
|
+
const take = (items, key) => {
|
|
66
|
+
const found = items.findIndex((p) => name(p.name) === key);
|
|
67
|
+
if (found < 0)
|
|
68
|
+
return;
|
|
69
|
+
const p = items.splice(found, 1)[0];
|
|
70
|
+
if (!ts.isPropertyAssignment(p))
|
|
71
|
+
throw new Error(`Cannot safely convert option ${key}`);
|
|
72
|
+
return p.initializer;
|
|
73
|
+
};
|
|
74
|
+
const set = (items, key, value) => {
|
|
75
|
+
if (items.some((p) => name(p.name) === key))
|
|
76
|
+
throw new Error(`Conflicting SvelteKit option ${key}; resolve manually.`);
|
|
77
|
+
items.push(ts.factory.createPropertyAssignment(key, value));
|
|
78
|
+
};
|
|
79
|
+
const nested = (key, edit) => {
|
|
80
|
+
const value = take(props, key);
|
|
81
|
+
if (!value)
|
|
82
|
+
return;
|
|
83
|
+
const items = [...object(value, source).properties];
|
|
84
|
+
edit(items);
|
|
85
|
+
if (items.length)
|
|
86
|
+
set(props, key, ts.factory.createObjectLiteralExpression(items, true));
|
|
87
|
+
};
|
|
88
|
+
const oldKit = take(props, 'kit');
|
|
89
|
+
if (oldKit)
|
|
90
|
+
for (const p of object(oldKit, source).properties) {
|
|
91
|
+
if (props.some((existing) => name(existing.name) && name(existing.name) === name(p.name)))
|
|
92
|
+
throw new Error(`Conflicting option ${name(p.name)}`);
|
|
93
|
+
props.push(p);
|
|
94
|
+
}
|
|
95
|
+
const vitePlugin = take(props, 'vitePlugin');
|
|
96
|
+
if (vitePlugin)
|
|
97
|
+
for (const p of object(vitePlugin, source).properties) {
|
|
98
|
+
if (props.some((existing) => name(existing.name) && name(existing.name) === name(p.name)))
|
|
99
|
+
throw new Error(`Conflicting option ${name(p.name)}`);
|
|
100
|
+
props.push(p);
|
|
101
|
+
}
|
|
102
|
+
take(props, 'preloadStrategy');
|
|
103
|
+
nested('files', (items) => {
|
|
104
|
+
take(items, 'lib');
|
|
105
|
+
});
|
|
106
|
+
nested('experimental', (items) => {
|
|
107
|
+
take(items, 'handleRenderingErrors');
|
|
108
|
+
take(items, 'instrumentation');
|
|
109
|
+
const tracing = take(items, 'tracing');
|
|
110
|
+
if (tracing)
|
|
111
|
+
set(props, 'tracing', tracing);
|
|
112
|
+
});
|
|
113
|
+
let origin;
|
|
114
|
+
nested('prerender', (items) => {
|
|
115
|
+
origin = take(items, 'origin');
|
|
116
|
+
});
|
|
117
|
+
if (origin) {
|
|
118
|
+
const paths = take(props, 'paths');
|
|
119
|
+
const items = paths ? [...object(paths, source).properties] : [];
|
|
120
|
+
set(items, 'origin', origin);
|
|
121
|
+
set(props, 'paths', ts.factory.createObjectLiteralExpression(items, true));
|
|
122
|
+
}
|
|
123
|
+
nested('csrf', (items) => {
|
|
124
|
+
const check = take(items, 'checkOrigin');
|
|
125
|
+
if (!check)
|
|
126
|
+
return;
|
|
127
|
+
if (check.kind === ts.SyntaxKind.FalseKeyword) {
|
|
128
|
+
if (items.some((p) => name(p.name) === 'trustedOrigins'))
|
|
129
|
+
throw new Error('Resolve csrf.checkOrigin and trustedOrigins manually.');
|
|
130
|
+
set(items, 'trustedOrigins', ts.factory.createArrayLiteralExpression([ts.factory.createStringLiteral('*')]));
|
|
131
|
+
}
|
|
132
|
+
else if (check.kind !== ts.SyntaxKind.TrueKeyword)
|
|
133
|
+
throw new Error('Dynamic csrf.checkOrigin requires manual migration.');
|
|
134
|
+
});
|
|
135
|
+
return print(ts.factory.createObjectLiteralExpression(props, true));
|
|
136
|
+
}
|
|
137
|
+
/** Pure config edit; never evaluates a project's configuration. */
|
|
138
|
+
export function mergeKitViteConfig(content, aliases, legacy) {
|
|
139
|
+
let source = parse(content);
|
|
140
|
+
const call = kitCall(source);
|
|
141
|
+
let options = call.arguments[0] ? object(call.arguments[0], source) : undefined;
|
|
142
|
+
let optionText = options ? modernOptions(options, source) : '{}';
|
|
143
|
+
if (legacy) {
|
|
144
|
+
if (options && options.properties.length)
|
|
145
|
+
throw new Error('Both Vite and legacy Svelte config contain options. Merge them with sv migrate sveltekit-3 first.');
|
|
146
|
+
const old = parse(legacy), exported = old.statements.find(ts.isExportAssignment);
|
|
147
|
+
if (!exported)
|
|
148
|
+
throw new Error('Legacy Svelte config has no default export.');
|
|
149
|
+
const root = object(exported.expression, old);
|
|
150
|
+
optionText = modernOptions(root, old);
|
|
151
|
+
const imports = old.statements.filter(ts.isImportDeclaration);
|
|
152
|
+
const bindings = (s) => {
|
|
153
|
+
const names = new Set();
|
|
154
|
+
for (const n of s.statements) {
|
|
155
|
+
if (ts.isImportDeclaration(n)) {
|
|
156
|
+
if (n.importClause?.name)
|
|
157
|
+
names.add(n.importClause.name.text);
|
|
158
|
+
const b = n.importClause?.namedBindings;
|
|
159
|
+
if (b && ts.isNamespaceImport(b))
|
|
160
|
+
names.add(b.name.text);
|
|
161
|
+
if (b && ts.isNamedImports(b))
|
|
162
|
+
for (const e of b.elements)
|
|
163
|
+
names.add(e.name.text);
|
|
164
|
+
}
|
|
165
|
+
if (ts.isVariableStatement(n))
|
|
166
|
+
for (const d of n.declarationList.declarations)
|
|
167
|
+
if (ts.isIdentifier(d.name))
|
|
168
|
+
names.add(d.name.text);
|
|
169
|
+
}
|
|
170
|
+
return names;
|
|
171
|
+
};
|
|
172
|
+
const oldNames = bindings(old);
|
|
173
|
+
const currentNames = bindings(source);
|
|
174
|
+
for (const n of oldNames)
|
|
175
|
+
if (currentNames.has(n))
|
|
176
|
+
throw new Error(`Config binding collision: ${n}. Run sv migrate sveltekit-3 first.`);
|
|
177
|
+
const rootStatement = old.statements.find((s) => ts.isVariableStatement(s) &&
|
|
178
|
+
s.declarationList.declarations.some((d) => d.initializer && objectOrUndefined(d.initializer, old) === root));
|
|
179
|
+
if (rootStatement && ts.isVariableStatement(rootStatement) && rootStatement.declarationList.declarations.length !== 1)
|
|
180
|
+
throw new Error('Split legacy config variable declarations before migration.');
|
|
181
|
+
for (const statement of old.statements)
|
|
182
|
+
if (!ts.isImportDeclaration(statement) &&
|
|
183
|
+
!ts.isExportAssignment(statement) &&
|
|
184
|
+
statement !== rootStatement &&
|
|
185
|
+
!ts.isEmptyStatement(statement))
|
|
186
|
+
throw new Error('Complex legacy config: run sv migrate sveltekit-3 first.');
|
|
187
|
+
const importText = imports.map((s) => s.getText(old)).join('\n');
|
|
188
|
+
content = content.slice(0, call.arguments.pos) + optionText + content.slice(call.arguments.end);
|
|
189
|
+
content = importText + '\n' + content;
|
|
190
|
+
source = parse(content);
|
|
191
|
+
const updated = kitCall(source);
|
|
192
|
+
options = object(updated.arguments[0], source);
|
|
193
|
+
}
|
|
194
|
+
const synthetic = mergeAliasesInSvelteConfig(`export default { kit: ${optionText} };`, aliases);
|
|
195
|
+
const merged = parse(synthetic).statements.find(ts.isExportAssignment);
|
|
196
|
+
const kit = merged.expression.properties[0];
|
|
197
|
+
const replacement = kit.initializer.getText(merged.getSourceFile());
|
|
198
|
+
if (options)
|
|
199
|
+
return content.slice(0, options.getStart(source)) + replacement + content.slice(options.end);
|
|
200
|
+
const actual = kitCall(source);
|
|
201
|
+
return content.slice(0, actual.arguments.pos) + replacement + content.slice(actual.arguments.end);
|
|
202
|
+
}
|
|
203
|
+
function objectOrUndefined(e, source) {
|
|
204
|
+
try {
|
|
205
|
+
return object(e, source);
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
export async function formatConfig(content, file) {
|
|
212
|
+
return format(content, { ...(await resolveConfig(file)), filepath: file, parser: 'typescript' });
|
|
213
|
+
}
|
|
214
|
+
export async function configureKitProject() {
|
|
215
|
+
const root = process.cwd();
|
|
216
|
+
const existing = async (names) => {
|
|
217
|
+
for (const n of names) {
|
|
218
|
+
try {
|
|
219
|
+
await fs.access(path.join(root, n));
|
|
220
|
+
return path.join(root, n);
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
if (error.code !== 'ENOENT')
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const vite = await existing(VITE_CONFIGS), legacy = await existing(SVELTE_CONFIGS);
|
|
229
|
+
if (!vite && !legacy) {
|
|
230
|
+
console.warn('No Vite config found; initialize a SvelteKit project first.');
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const file = vite ?? path.join(root, 'vite.config.ts');
|
|
234
|
+
const content = vite
|
|
235
|
+
? await fs.readFile(vite, 'utf8')
|
|
236
|
+
: "import { defineConfig } from 'vite';\nimport { sveltekit } from '@sveltejs/kit/vite';\nexport default defineConfig({plugins: [sveltekit()]});\n";
|
|
237
|
+
const old = legacy ? await fs.readFile(legacy, 'utf8') : undefined;
|
|
238
|
+
const next = await formatConfig(mergeKitViteConfig(content, ARCHITECTURE_ALIASES, old), file);
|
|
239
|
+
if (legacy) {
|
|
240
|
+
const backup = await fs.mkdtemp(path.join(await fs
|
|
241
|
+
.mkdir(path.join(root, '.azure-net/ConfigBackups'), { recursive: true })
|
|
242
|
+
.then(() => path.join(root, '.azure-net/ConfigBackups')), 'kit3-'));
|
|
243
|
+
await fs.writeFile(path.join(backup, path.basename(legacy)), old);
|
|
244
|
+
if (vite)
|
|
245
|
+
await fs.writeFile(path.join(backup, path.basename(vite)), content);
|
|
246
|
+
}
|
|
247
|
+
await fs.writeFile(file, next);
|
|
248
|
+
if (legacy)
|
|
249
|
+
await fs.unlink(legacy);
|
|
250
|
+
}
|
|
251
|
+
export function readStaticAliases(content) {
|
|
252
|
+
const aliases = {};
|
|
253
|
+
const source = parse(content);
|
|
254
|
+
const visit = (n) => {
|
|
255
|
+
if (ts.isPropertyAssignment(n) && name(n.name) === 'alias') {
|
|
256
|
+
const value = objectOrUndefined(n.initializer, source);
|
|
257
|
+
if (value)
|
|
258
|
+
for (const p of value.properties)
|
|
259
|
+
if (ts.isPropertyAssignment(p) && name(p.name) && ts.isStringLiteral(p.initializer))
|
|
260
|
+
aliases[name(p.name)] = p.initializer.text;
|
|
261
|
+
}
|
|
262
|
+
ts.forEachChild(n, visit);
|
|
263
|
+
};
|
|
264
|
+
visit(source);
|
|
265
|
+
return aliases;
|
|
266
|
+
}
|
|
267
|
+
/** Hydratable needs Svelte async mode. Preserve all unrelated literal options. */
|
|
268
|
+
export function enableHydratable(content) {
|
|
269
|
+
const source = parse(content);
|
|
270
|
+
const call = kitCall(source);
|
|
271
|
+
const update = (value, keys) => {
|
|
272
|
+
const key = keys[0];
|
|
273
|
+
const props = [...value.properties];
|
|
274
|
+
const existing = props.find((p) => name(p.name) === key);
|
|
275
|
+
if (existing && !ts.isPropertyAssignment(existing))
|
|
276
|
+
throw new Error(`Cannot safely configure ${keys.join('.')}. Use literal compilerOptions.`);
|
|
277
|
+
if (props.some(ts.isSpreadAssignment))
|
|
278
|
+
throw new Error('Cannot safely enable async mode in spread options. Set compilerOptions.experimental.async: true manually.');
|
|
279
|
+
const next = keys.length === 1
|
|
280
|
+
? ts.factory.createTrue()
|
|
281
|
+
: update(existing ? object(existing.initializer, source) : ts.factory.createObjectLiteralExpression(), keys.slice(1));
|
|
282
|
+
const index = props.findIndex((p) => name(p.name) === key);
|
|
283
|
+
const property = ts.factory.createPropertyAssignment(key, next);
|
|
284
|
+
if (index === -1)
|
|
285
|
+
props.push(property);
|
|
286
|
+
else
|
|
287
|
+
props[index] = property;
|
|
288
|
+
return ts.factory.createObjectLiteralExpression(props, true);
|
|
289
|
+
};
|
|
290
|
+
const options = call.arguments[0] ? object(call.arguments[0], source) : ts.factory.createObjectLiteralExpression();
|
|
291
|
+
const updated = update(options, ['compilerOptions', 'experimental', 'async']);
|
|
292
|
+
return (content.slice(0, call.getStart(source)) +
|
|
293
|
+
`${call.expression.getText(source)}(${ts.createPrinter().printNode(ts.EmitHint.Expression, updated, source)})` +
|
|
294
|
+
content.slice(call.end));
|
|
295
|
+
}
|