@azure-net/cli 5.1.0 → 6.0.0-next.2

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.
Files changed (176) hide show
  1. package/README.md +189 -0
  2. package/bin/azure-net.js +236 -221
  3. package/dist/bin/azure-net.d.ts +2 -0
  4. package/dist/src/checks/architecture.d.ts +20 -0
  5. package/dist/src/checks/checkDomain.d.ts +1 -0
  6. package/dist/src/checks/checkFoldersStructure.d.ts +1 -0
  7. package/dist/src/checks/checkHooks.d.ts +1 -0
  8. package/dist/src/checks/checkImports.d.ts +1 -0
  9. package/dist/src/checks/checkInternal.d.ts +1 -0
  10. package/dist/src/checks/checkLayerBoundaries.d.ts +1 -0
  11. package/dist/src/checks/checkLayerImports.d.ts +1 -0
  12. package/dist/src/checks/checkPresenterNames.d.ts +1 -0
  13. package/dist/src/checks/checkProject.d.ts +1 -0
  14. package/dist/src/checks/checkProviderGraph.d.ts +1 -0
  15. package/dist/src/checks/checkProviderNames.d.ts +1 -0
  16. package/dist/src/generate/layers/generateRepository.d.ts +1 -0
  17. package/dist/src/generate/layers/generateRepositoryMethod.d.ts +1 -0
  18. package/dist/src/generate/layers/generateUseCases.d.ts +1 -0
  19. package/dist/src/generate/module/generateDomain.d.ts +8 -0
  20. package/dist/src/generate/module/generateModule.d.ts +1 -0
  21. package/dist/src/generate/module/generateModulePreset.d.ts +1 -0
  22. package/dist/src/generate/module/generatePresenter.d.ts +29 -0
  23. package/dist/src/generate/module/generateRepository.d.ts +15 -0
  24. package/dist/src/generate/module/generateRepositoryMethod.d.ts +2 -0
  25. package/dist/src/generate/module/generateSchemaFromType.d.ts +9 -0
  26. package/dist/src/generate/module/generateStore.d.ts +1 -0
  27. package/dist/src/generate/module/generateTypesJson.d.ts +2 -0
  28. package/dist/src/generate/module/generateUseCases.d.ts +1 -0
  29. package/dist/src/generate/module/repositoryModuleShared.d.ts +89 -0
  30. package/dist/src/generate/routes/generateRoutes.d.ts +14 -0
  31. package/dist/src/generate/ui/generateComponent.d.ts +1 -0
  32. package/dist/src/generate/ui/generateDesignComponent.d.ts +1 -0
  33. package/dist/src/generate/ui/generateWidget.d.ts +1 -0
  34. package/dist/src/git/commit.d.ts +23 -0
  35. package/dist/src/git/push.d.ts +11 -0
  36. package/dist/src/git/runGit.d.ts +2 -0
  37. package/dist/src/init/initAliases.d.ts +12 -0
  38. package/dist/src/init/initEdges.d.ts +2 -0
  39. package/dist/src/init/initStructure.d.ts +1 -0
  40. package/dist/src/install/configureCommitTools.d.ts +1 -0
  41. package/dist/src/install/installFresh.d.ts +1 -0
  42. package/dist/src/migrate/migrate.d.ts +22 -0
  43. package/dist/src/migrate/presenters.d.ts +7 -0
  44. package/dist/src/plugins/addLint.d.ts +5 -0
  45. package/dist/src/scaffolds/createCoreSchema.d.ts +1 -0
  46. package/dist/src/scaffolds/createDatasource.d.ts +1 -0
  47. package/dist/src/scaffolds/createProgram.d.ts +1 -0
  48. package/dist/src/scaffolds/createResponse.d.ts +1 -0
  49. package/dist/src/scaffolds/createSchemaRule.d.ts +1 -0
  50. package/dist/src/scaffolds/createTranslationManager.d.ts +1 -0
  51. package/{src/scaffolds/index.ts → dist/src/scaffolds/index.d.ts} +0 -2
  52. package/dist/src/scaffolds/registerDatasource.d.ts +2 -0
  53. package/dist/src/scaffolds/updateDefaultFactoryConfig.d.ts +1 -0
  54. package/dist/src/utils/architecture.d.ts +31 -0
  55. package/dist/src/utils/contextUtils.d.ts +6 -0
  56. package/dist/src/utils/fileUtils.d.ts +5 -0
  57. package/dist/src/utils/flattenConfig.d.ts +2 -0
  58. package/dist/src/utils/legacyAliases.d.ts +1 -0
  59. package/dist/src/utils/loadConfig.d.ts +16 -0
  60. package/dist/src/utils/packageImports.d.ts +4 -0
  61. package/dist/src/utils/sharedFoundation.d.ts +20 -0
  62. package/dist/src/utils/viteConfig.d.ts +9 -0
  63. package/package.json +48 -36
  64. package/src/checks/architecture.js +154 -0
  65. package/src/checks/checkDomain.js +124 -154
  66. package/src/checks/checkFoldersStructure.js +64 -52
  67. package/src/checks/checkHooks.js +12 -12
  68. package/src/checks/checkImports.js +26 -142
  69. package/src/checks/checkInternal.js +27 -24
  70. package/src/checks/checkLayerBoundaries.js +22 -197
  71. package/src/checks/checkLayerImports.js +14 -134
  72. package/src/checks/checkPresenterNames.js +156 -143
  73. package/src/checks/checkProject.js +27 -26
  74. package/src/checks/checkProviderGraph.js +182 -166
  75. package/src/checks/checkProviderNames.js +123 -112
  76. package/src/generate/layers/generateRepository.js +1 -109
  77. package/src/generate/layers/generateRepositoryMethod.js +1 -90
  78. package/src/generate/layers/generateUseCases.js +1 -44
  79. package/src/generate/module/generateDomain.js +81 -105
  80. package/src/generate/module/generateModule.js +34 -68
  81. package/src/generate/module/generateModulePreset.js +188 -248
  82. package/src/generate/module/generatePresenter.js +441 -369
  83. package/src/generate/module/generateRepository.js +102 -121
  84. package/src/generate/module/generateRepositoryMethod.js +117 -0
  85. package/src/generate/module/generateSchemaFromType.js +283 -280
  86. package/src/generate/module/generateStore.js +41 -0
  87. package/src/generate/module/generateTypesJson.js +196 -195
  88. package/src/generate/module/generateUseCases.js +47 -55
  89. package/src/generate/module/repositoryModuleShared.js +480 -459
  90. package/src/generate/routes/generateRoutes.js +165 -174
  91. package/src/generate/ui/generateComponent.js +44 -64
  92. package/src/generate/ui/generateDesignComponent.js +21 -41
  93. package/src/generate/ui/generateWidget.js +21 -41
  94. package/src/git/commit.js +67 -0
  95. package/src/git/push.js +19 -0
  96. package/src/git/runGit.js +11 -0
  97. package/src/init/initAliases.js +19 -135
  98. package/src/init/initEdges.js +79 -54
  99. package/src/init/initStructure.js +31 -145
  100. package/src/install/configureCommitTools.js +1 -0
  101. package/src/install/installFresh.js +39 -68
  102. package/src/migrate/migrate.js +914 -0
  103. package/src/migrate/presenters.js +265 -0
  104. package/src/plugins/addLint.js +52 -219
  105. package/src/scaffolds/createCoreSchema.js +65 -91
  106. package/src/scaffolds/createDatasource.js +67 -101
  107. package/src/scaffolds/createProgram.js +8 -8
  108. package/src/scaffolds/createResponse.js +29 -29
  109. package/src/scaffolds/createSchemaRule.js +19 -19
  110. package/src/scaffolds/createTranslationManager.js +84 -37
  111. package/src/scaffolds/index.js +0 -2
  112. package/src/scaffolds/registerDatasource.js +59 -0
  113. package/src/scaffolds/updateDefaultFactoryConfig.js +31 -0
  114. package/src/utils/architecture.js +145 -0
  115. package/src/utils/contextUtils.js +32 -65
  116. package/src/utils/fileUtils.js +69 -50
  117. package/src/utils/flattenConfig.js +38 -0
  118. package/src/utils/legacyAliases.js +75 -0
  119. package/src/utils/loadConfig.js +76 -40
  120. package/src/utils/packageImports.js +63 -0
  121. package/src/utils/sharedFoundation.js +36 -42
  122. package/src/utils/viteConfig.js +295 -0
  123. package/.prettierrc +0 -7
  124. package/bin/azure-net.ts +0 -308
  125. package/eslint.config.js +0 -34
  126. package/src/checks/checkDomain.ts +0 -223
  127. package/src/checks/checkFoldersStructure.ts +0 -85
  128. package/src/checks/checkHooks.ts +0 -22
  129. package/src/checks/checkImports.ts +0 -193
  130. package/src/checks/checkInternal.ts +0 -48
  131. package/src/checks/checkLayerBoundaries.ts +0 -255
  132. package/src/checks/checkLayerImports.ts +0 -185
  133. package/src/checks/checkPresenterNames.ts +0 -203
  134. package/src/checks/checkProject.ts +0 -45
  135. package/src/checks/checkProviderGraph.ts +0 -234
  136. package/src/checks/checkProviderNames.ts +0 -165
  137. package/src/generate/layers/generateRepository.ts +0 -123
  138. package/src/generate/layers/generateRepositoryMethod.ts +0 -102
  139. package/src/generate/layers/generateUseCases.ts +0 -50
  140. package/src/generate/layers/repositoryShared.js +0 -506
  141. package/src/generate/layers/repositoryShared.ts +0 -662
  142. package/src/generate/module/generateDomain.ts +0 -147
  143. package/src/generate/module/generateModule.ts +0 -84
  144. package/src/generate/module/generateModulePreset.ts +0 -338
  145. package/src/generate/module/generatePresenter.ts +0 -498
  146. package/src/generate/module/generateRepository.ts +0 -158
  147. package/src/generate/module/generateSchemaFromType.ts +0 -368
  148. package/src/generate/module/generateTypesJson.ts +0 -259
  149. package/src/generate/module/generateUseCases.ts +0 -67
  150. package/src/generate/module/repositoryModuleShared.ts +0 -669
  151. package/src/generate/routes/generateRoutes.ts +0 -282
  152. package/src/generate/ui/generateComponent.ts +0 -100
  153. package/src/generate/ui/generateDesignComponent.ts +0 -71
  154. package/src/generate/ui/generateWidget.ts +0 -71
  155. package/src/init/initAliases.ts +0 -172
  156. package/src/init/initEdges.ts +0 -74
  157. package/src/init/initStructure.ts +0 -172
  158. package/src/install/installFresh.ts +0 -93
  159. package/src/plugins/addLint.ts +0 -274
  160. package/src/scaffolds/createCoreSchema.ts +0 -130
  161. package/src/scaffolds/createDatasource.ts +0 -161
  162. package/src/scaffolds/createDatasourceProvider.js +0 -127
  163. package/src/scaffolds/createDatasourceProvider.ts +0 -161
  164. package/src/scaffolds/createPresenterFactory.js +0 -83
  165. package/src/scaffolds/createPresenterFactory.ts +0 -102
  166. package/src/scaffolds/createProgram.ts +0 -19
  167. package/src/scaffolds/createResponse.ts +0 -66
  168. package/src/scaffolds/createSchemaRule.ts +0 -44
  169. package/src/scaffolds/createTranslationManager.ts +0 -80
  170. package/src/utils/contextUtils.ts +0 -88
  171. package/src/utils/fileUtils.ts +0 -74
  172. package/src/utils/loadConfig.ts +0 -68
  173. package/src/utils/sharedFoundation.ts +0 -70
  174. package/tsconfig.json +0 -19
  175. /package/{src/checks/index.ts → dist/src/checks/index.d.ts} +0 -0
  176. /package/{src/plugins/index.ts → dist/src/plugins/index.d.ts} +0 -0
@@ -1,282 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import prompts from 'prompts';
4
- import { loadUserConfig } from '../../utils/loadConfig.js';
5
- import { getSharedContextRootPath, getSharedState } from '../../utils/sharedFoundation.js';
6
- import { toCamelCase } from '../../utils/contextUtils.js';
7
-
8
- type RouteGroupingMode = 'root-groups' | 'config-function' | 'none';
9
-
10
- export type RouteGenerationMeta = {
11
- url: string;
12
- routeDir: string;
13
- relativeDir: string;
14
- segments: string[];
15
- dynamicParams: string[];
16
- rootGroup?: string;
17
- groupStack: string[];
18
- depth: number;
19
- hasChildren: boolean;
20
- hasPage: boolean;
21
- hasServer: boolean;
22
- };
23
-
24
- type RouteRecord = RouteGenerationMeta;
25
- type RouteGroupResolver = (route: RouteGenerationMeta) => string | null | undefined;
26
-
27
- const ROUTES_DIR = path.join(process.cwd(), 'src', 'routes');
28
- const ROUTE_FILE_PATTERN = /^\+(page|server)(?:\.server)?\.(?:svelte|ts|js)$/;
29
- const PAGE_FILE_PATTERN = /^\+page(?:\.server)?\.(?:svelte|ts|js)$/;
30
- const SERVER_FILE_PATTERN = /^\+server\.(?:ts|js)$/;
31
-
32
- const isRouteGroup = (segment: string): boolean => /^\(.+\)$/.test(segment);
33
- const getRouteGroupName = (segment: string): string => segment.slice(1, -1).trim();
34
-
35
- const extractParamName = (rawParam: string): string => {
36
- const withoutRest = rawParam.startsWith('...') ? rawParam.slice(3) : rawParam;
37
- const matcherIndex = withoutRest.indexOf('=');
38
- return matcherIndex === -1 ? withoutRest : withoutRest.slice(0, matcherIndex);
39
- };
40
-
41
- const convertDynamicSegments = (segment: string): { variants: string[]; params: string[] } => {
42
- const optionalMatch = segment.match(/^\[\[(.+)\]\]$/);
43
- if (optionalMatch?.[1]) {
44
- const paramName = extractParamName(optionalMatch[1]);
45
- return { variants: ['', `{${paramName}}`], params: [paramName] };
46
- }
47
-
48
- const params: string[] = [];
49
- const converted = segment.replace(/\[(.+?)\]/g, (_match, rawParam: string) => {
50
- const paramName = extractParamName(rawParam);
51
- if (paramName.length) params.push(paramName);
52
- return `{${paramName}}`;
53
- });
54
-
55
- return { variants: [converted], params };
56
- };
57
-
58
- const normalizeUrl = (segments: string[]): string => {
59
- const filtered = segments.filter(Boolean);
60
- return filtered.length ? `/${filtered.join('/')}` : '/';
61
- };
62
-
63
- const createRouteVariants = (segments: string[]): { urls: string[]; dynamicParams: string[] } => {
64
- let variants: string[][] = [[]];
65
- const dynamicParams = new Set<string>();
66
-
67
- for (const segment of segments) {
68
- if (isRouteGroup(segment)) continue;
69
-
70
- const converted = convertDynamicSegments(segment);
71
- for (const param of converted.params) {
72
- dynamicParams.add(param);
73
- }
74
-
75
- const nextVariants: string[][] = [];
76
- for (const variant of variants) {
77
- for (const nextSegment of converted.variants) {
78
- nextVariants.push(nextSegment ? [...variant, nextSegment] : [...variant]);
79
- }
80
- }
81
- variants = nextVariants;
82
- }
83
-
84
- return {
85
- urls: [...new Set(variants.map(normalizeUrl))],
86
- dynamicParams: [...dynamicParams]
87
- };
88
- };
89
-
90
- const hasRouteFile = (files: string[]): boolean => files.some((file) => ROUTE_FILE_PATTERN.test(file));
91
- const hasPageFile = (files: string[]): boolean => files.some((file) => PAGE_FILE_PATTERN.test(file));
92
- const hasServerFile = (files: string[]): boolean => files.some((file) => SERVER_FILE_PATTERN.test(file));
93
-
94
- const readDirSafe = async (dir: string): Promise<import('node:fs').Dirent[]> => {
95
- try {
96
- return await fs.readdir(dir, { withFileTypes: true });
97
- } catch {
98
- return [];
99
- }
100
- };
101
-
102
- const collectRoutes = async (
103
- dir: string,
104
- segments: string[] = [],
105
- groupStack: string[] = [],
106
- rootGroup?: string
107
- ): Promise<RouteRecord[]> => {
108
- const entries = (await readDirSafe(dir)).sort((a, b) => a.name.localeCompare(b.name));
109
- const files = entries.filter((entry) => entry.isFile()).map((entry) => entry.name);
110
- const dirs = entries.filter((entry) => entry.isDirectory() && !entry.name.startsWith('.'));
111
- const routes: RouteRecord[] = [];
112
- const routeVariants = createRouteVariants(segments);
113
-
114
- if (hasRouteFile(files)) {
115
- for (const url of routeVariants.urls) {
116
- routes.push({
117
- url,
118
- routeDir: dir,
119
- relativeDir: path.relative(ROUTES_DIR, dir) || '.',
120
- segments,
121
- dynamicParams: routeVariants.dynamicParams,
122
- rootGroup,
123
- groupStack,
124
- depth: segments.length,
125
- hasChildren: dirs.length > 0,
126
- hasPage: hasPageFile(files),
127
- hasServer: hasServerFile(files)
128
- });
129
- }
130
- }
131
-
132
- for (const child of dirs) {
133
- const childGroupName = isRouteGroup(child.name) ? getRouteGroupName(child.name) : undefined;
134
- const nextGroupStack = childGroupName ? [...groupStack, childGroupName] : groupStack;
135
- const nextRootGroup = rootGroup ?? (segments.length === 0 ? childGroupName : undefined);
136
- const childRoutes = await collectRoutes(path.join(dir, child.name), [...segments, child.name], nextGroupStack, nextRootGroup);
137
- routes.push(...childRoutes);
138
- }
139
-
140
- return routes;
141
- };
142
-
143
- const sanitizeGroupName = (value: string): string => {
144
- const trimmed = value.trim();
145
- return trimmed.length ? trimmed : 'routes';
146
- };
147
-
148
- const toRouteVariableName = (groupName: string): string => {
149
- const base = toCamelCase(sanitizeGroupName(groupName).replace(/[^\p{L}\p{N}_-]+/gu, '-'));
150
- return `${base || 'routes'}Routes`;
151
- };
152
-
153
- const ensureUniqueVariableName = (name: string, used: Set<string>): string => {
154
- if (!used.has(name)) {
155
- used.add(name);
156
- return name;
157
- }
158
-
159
- let index = 2;
160
- let nextName = `${name}${index}`;
161
- while (used.has(nextName)) {
162
- index += 1;
163
- nextName = `${name}${index}`;
164
- }
165
- used.add(nextName);
166
- return nextName;
167
- };
168
-
169
- const createGroupMap = (routes: RouteRecord[], mode: RouteGroupingMode, resolver?: RouteGroupResolver): Map<string, RouteRecord[]> => {
170
- const groups = new Map<string, RouteRecord[]>();
171
-
172
- for (const route of routes) {
173
- const groupName =
174
- mode === 'none'
175
- ? 'routes'
176
- : mode === 'root-groups'
177
- ? (route.rootGroup ?? 'routes')
178
- : (sanitizeGroupName(String(resolver?.(route) ?? 'routes')) ?? 'routes');
179
- const list = groups.get(groupName) ?? [];
180
- list.push(route);
181
- groups.set(groupName, list);
182
- }
183
-
184
- return groups;
185
- };
186
-
187
- const createStringArray = (items: string[], indent = '\t'): string => {
188
- if (!items.length) return '[]';
189
- return `[\n${items.map((item) => `${indent}'${item}'`).join(',\n')}\n]`;
190
- };
191
-
192
- const createGeneratedFile = (groups: Map<string, RouteRecord[]>): string => {
193
- const usedVariables = new Set<string>();
194
- const groupEntries = [...groups.entries()].map(([groupName, routes]) => ({
195
- groupName,
196
- variableName: ensureUniqueVariableName(
197
- groupName === 'routes' ? (groups.size === 1 ? 'routes' : 'ungroupedRoutes') : toRouteVariableName(groupName),
198
- usedVariables
199
- ),
200
- routes: [...new Set(routes.map((route) => route.url))].sort((a, b) => a.localeCompare(b))
201
- }));
202
-
203
- const lines: string[] = ['// This file is generated by `azure-net generate routes`.', '// Do not edit it manually.', ''];
204
-
205
- for (const group of groupEntries) {
206
- lines.push(`export const ${group.variableName} = ${createStringArray(group.routes)} as const;`);
207
- lines.push('');
208
- }
209
-
210
- if (groupEntries.length !== 1 || groupEntries[0]?.variableName !== 'routes') {
211
- lines.push(`export const routes = [${groupEntries.map((group) => `...${group.variableName}`).join(', ')}] as const;`);
212
- lines.push('');
213
- }
214
-
215
- lines.push('export const routeGroups = {');
216
- lines.push(
217
- ...groupEntries.map((group, index) => `\t'${group.groupName}': ${group.variableName}${index === groupEntries.length - 1 ? '' : ','}`)
218
- );
219
- lines.push('} as const;');
220
- lines.push('');
221
- lines.push('export type Route = (typeof routes)[number];');
222
- lines.push('export type RouteGroupName = keyof typeof routeGroups;');
223
- lines.push('');
224
-
225
- return `${lines.join('\n')}\n`;
226
- };
227
-
228
- const selectGroupingMode = async (): Promise<RouteGroupingMode | null> => {
229
- const { mode } = await prompts({
230
- type: 'select',
231
- name: 'mode',
232
- message: 'How should routes be grouped?',
233
- choices: [
234
- { title: 'By root route groups: (account), (landing), ...', value: 'root-groups' },
235
- { title: 'By azure-net.config.ts groupRoutesFunc', value: 'config-function' },
236
- { title: 'Do not group, generate one routes array', value: 'none' }
237
- ]
238
- });
239
-
240
- return mode ? (mode as RouteGroupingMode) : null;
241
- };
242
-
243
- const getConfigRouteGroupResolver = async (): Promise<RouteGroupResolver | null> => {
244
- const config = await loadUserConfig();
245
- if (typeof config.groupRoutesFunc !== 'function') {
246
- console.error('❌ `groupRoutesFunc` is missing in azure-net.config.ts/js or is not a function.');
247
- console.error('Example:');
248
- console.error('export default {');
249
- console.error("\tgroupRoutesFunc: (route) => route.rootGroup ?? 'app'");
250
- console.error('};');
251
- return null;
252
- }
253
-
254
- return config.groupRoutesFunc as RouteGroupResolver;
255
- };
256
-
257
- export default async function generateRoutes(): Promise<void> {
258
- const mode = await selectGroupingMode();
259
- if (!mode) return;
260
-
261
- const { sharedContext } = await getSharedState();
262
- const resolver = mode === 'config-function' ? await getConfigRouteGroupResolver() : undefined;
263
- if (mode === 'config-function' && !resolver) {
264
- process.exitCode = 1;
265
- return;
266
- }
267
-
268
- const routes = await collectRoutes(ROUTES_DIR);
269
- if (!routes.length) {
270
- console.warn('⚠️ No SvelteKit routes found in src/routes');
271
- return;
272
- }
273
-
274
- const groups = createGroupMap(routes, mode, resolver ?? undefined);
275
- const outputDir = path.join(getSharedContextRootPath(sharedContext.name), 'runtime', 'routes');
276
- const outputFile = path.join(outputDir, 'index.ts');
277
-
278
- await fs.mkdir(outputDir, { recursive: true });
279
- await fs.writeFile(outputFile, createGeneratedFile(groups), 'utf-8');
280
-
281
- console.log(`✅ Routes generated: ${outputFile}`);
282
- }
@@ -1,100 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import prompts from 'prompts';
4
- import { toPascalCase } from '../../utils/contextUtils.js';
5
- import { normalizeContexts } from '../../init/initAliases.js';
6
- import { loadUserConfig } from '../../utils/loadConfig.js';
7
- import { writeIfNotExists } from '../../utils/fileUtils.js';
8
-
9
- type ComponentKind = 'shared' | 'layout' | 'page';
10
-
11
- const createComponentContent = (propsName: string): string => `<script lang="ts">
12
- import type { ${propsName} } from './types';
13
- const {}: ${propsName} = $props();
14
- </script>
15
- <!--Your HTML here-->
16
- <style lang="scss">
17
- \t@use './style';
18
- </style>
19
- `;
20
-
21
- const createTypesContent = (propsName: string): string => `export interface ${propsName} {}
22
- `;
23
-
24
- const createIndexContent = (name: string): string => `export { default as ${name} } from './Component.svelte';
25
- `;
26
-
27
- const printContextsError = (): void => {
28
- console.error('❌ Cannot generate UI artifact: `contexts` is missing or empty in azure-net.config.ts/js');
29
- };
30
-
31
- const selectContext = async (): Promise<string | null> => {
32
- const config = await loadUserConfig();
33
- const contexts = normalizeContexts(config.contexts);
34
- if (!contexts.length) return null;
35
-
36
- const { context } = await prompts({
37
- type: 'select',
38
- name: 'context',
39
- message: 'Select context:',
40
- choices: contexts.map((item) => ({ title: item.name, value: item.name })),
41
- initial: 0
42
- });
43
-
44
- return context ? String(context) : null;
45
- };
46
-
47
- export default async function generateComponent(): Promise<void> {
48
- const context = await selectContext();
49
- if (!context) {
50
- printContextsError();
51
- process.exitCode = 1;
52
- return;
53
- }
54
-
55
- const { rawName } = await prompts({
56
- type: 'text',
57
- name: 'rawName',
58
- message: 'Component name:',
59
- validate: (value: string) => (String(value).trim().length > 0 ? true : 'Name is required')
60
- });
61
-
62
- const { componentKind } = await prompts({
63
- type: 'select',
64
- name: 'componentKind',
65
- message: 'Component kind:',
66
- choices: [
67
- { title: 'shared', value: 'shared' },
68
- { title: 'layout', value: 'layout' },
69
- { title: 'page', value: 'page' }
70
- ],
71
- initial: 0
72
- });
73
-
74
- const name = toPascalCase(String(rawName ?? 'Component')) || 'Component';
75
- const propsName = `IComponent${name}Props`;
76
- const kind = (componentKind as ComponentKind) ?? 'shared';
77
- let targetDir = path.join(process.cwd(), 'src', 'app', context, 'ui', 'components', kind);
78
-
79
- if (kind === 'page') {
80
- const { pageFolderRaw } = await prompts({
81
- type: 'text',
82
- name: 'pageFolderRaw',
83
- message: 'Page folder name:',
84
- validate: (value: string) => (String(value).trim().length > 0 ? true : 'Page folder name is required')
85
- });
86
-
87
- const pageFolder = String(pageFolderRaw ?? '').trim();
88
- targetDir = path.join(targetDir, pageFolder);
89
- }
90
-
91
- targetDir = path.join(targetDir, name);
92
-
93
- await fs.mkdir(targetDir, { recursive: true });
94
- await writeIfNotExists(path.join(targetDir, 'Component.svelte'), createComponentContent(propsName));
95
- await writeIfNotExists(path.join(targetDir, 'style.scss'), '');
96
- await writeIfNotExists(path.join(targetDir, 'types.ts'), createTypesContent(propsName));
97
- await writeIfNotExists(path.join(targetDir, 'index.ts'), createIndexContent(name));
98
-
99
- console.log(`✅ Component generated: ${targetDir}`);
100
- }
@@ -1,71 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import prompts from 'prompts';
4
- import { toPascalCase } from '../../utils/contextUtils.js';
5
- import { normalizeContexts } from '../../init/initAliases.js';
6
- import { loadUserConfig } from '../../utils/loadConfig.js';
7
- import { writeIfNotExists } from '../../utils/fileUtils.js';
8
-
9
- const createComponentContent = (propsName: string): string => `<script lang="ts">
10
- import type { ${propsName} } from './types';
11
- const {}: ${propsName} = $props();
12
- </script>
13
- <!--Your HTML here-->
14
- <style lang="scss">
15
- \t@use './style';
16
- </style>
17
- `;
18
-
19
- const createTypesContent = (propsName: string): string => `export interface ${propsName} {}
20
- `;
21
-
22
- const createIndexContent = (name: string): string => `export { default as ${name} } from './Component.svelte';
23
- `;
24
-
25
- const printContextsError = (): void => {
26
- console.error('❌ Cannot generate UI artifact: `contexts` is missing or empty in azure-net.config.ts/js');
27
- };
28
-
29
- const selectContext = async (): Promise<string | null> => {
30
- const config = await loadUserConfig();
31
- const contexts = normalizeContexts(config.contexts);
32
- if (!contexts.length) return null;
33
-
34
- const { context } = await prompts({
35
- type: 'select',
36
- name: 'context',
37
- message: 'Select context:',
38
- choices: contexts.map((item) => ({ title: item.name, value: item.name })),
39
- initial: 0
40
- });
41
-
42
- return context ? String(context) : null;
43
- };
44
-
45
- export default async function generateDesignComponent(): Promise<void> {
46
- const context = await selectContext();
47
- if (!context) {
48
- printContextsError();
49
- process.exitCode = 1;
50
- return;
51
- }
52
-
53
- const { rawName } = await prompts({
54
- type: 'text',
55
- name: 'rawName',
56
- message: 'Design component name:',
57
- validate: (value: string) => (String(value).trim().length > 0 ? true : 'Name is required')
58
- });
59
-
60
- const name = toPascalCase(String(rawName ?? 'DesignComponent')) || 'DesignComponent';
61
- const propsName = `IDesignComponent${name}Props`;
62
- const targetDir = path.join(process.cwd(), 'src', 'app', context, 'ui', 'design', name);
63
-
64
- await fs.mkdir(targetDir, { recursive: true });
65
- await writeIfNotExists(path.join(targetDir, 'Component.svelte'), createComponentContent(propsName));
66
- await writeIfNotExists(path.join(targetDir, 'style.scss'), '');
67
- await writeIfNotExists(path.join(targetDir, 'types.ts'), createTypesContent(propsName));
68
- await writeIfNotExists(path.join(targetDir, 'index.ts'), createIndexContent(name));
69
-
70
- console.log(`✅ Design component generated: ${targetDir}`);
71
- }
@@ -1,71 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import prompts from 'prompts';
4
- import { toPascalCase } from '../../utils/contextUtils.js';
5
- import { normalizeContexts } from '../../init/initAliases.js';
6
- import { loadUserConfig } from '../../utils/loadConfig.js';
7
- import { writeIfNotExists } from '../../utils/fileUtils.js';
8
-
9
- const createComponentContent = (propsName: string): string => `<script lang="ts">
10
- import type { ${propsName} } from './types';
11
- const {}: ${propsName} = $props();
12
- </script>
13
- <!--Your HTML here-->
14
- <style lang="scss">
15
- \t@use './style';
16
- </style>
17
- `;
18
-
19
- const createTypesContent = (propsName: string): string => `export interface ${propsName} {}
20
- `;
21
-
22
- const createIndexContent = (name: string): string => `export { default as ${name} } from './Component.svelte';
23
- `;
24
-
25
- const printContextsError = (): void => {
26
- console.error('❌ Cannot generate UI artifact: `contexts` is missing or empty in azure-net.config.ts/js');
27
- };
28
-
29
- const selectContext = async (): Promise<string | null> => {
30
- const config = await loadUserConfig();
31
- const contexts = normalizeContexts(config.contexts);
32
- if (!contexts.length) return null;
33
-
34
- const { context } = await prompts({
35
- type: 'select',
36
- name: 'context',
37
- message: 'Select context:',
38
- choices: contexts.map((item) => ({ title: item.name, value: item.name })),
39
- initial: 0
40
- });
41
-
42
- return context ? String(context) : null;
43
- };
44
-
45
- export default async function generateWidget(): Promise<void> {
46
- const context = await selectContext();
47
- if (!context) {
48
- printContextsError();
49
- process.exitCode = 1;
50
- return;
51
- }
52
-
53
- const { rawName } = await prompts({
54
- type: 'text',
55
- name: 'rawName',
56
- message: 'Widget name:',
57
- validate: (value: string) => (String(value).trim().length > 0 ? true : 'Name is required')
58
- });
59
-
60
- const name = toPascalCase(String(rawName ?? 'Widget')) || 'Widget';
61
- const propsName = `IWidget${name}Props`;
62
- const targetDir = path.join(process.cwd(), 'src', 'app', context, 'ui', 'widgets', name);
63
-
64
- await fs.mkdir(targetDir, { recursive: true });
65
- await writeIfNotExists(path.join(targetDir, 'Component.svelte'), createComponentContent(propsName));
66
- await writeIfNotExists(path.join(targetDir, 'style.scss'), '');
67
- await writeIfNotExists(path.join(targetDir, 'types.ts'), createTypesContent(propsName));
68
- await writeIfNotExists(path.join(targetDir, 'index.ts'), createIndexContent(name));
69
-
70
- console.log(`✅ Widget generated: ${targetDir}`);
71
- }
@@ -1,172 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import { loadUserConfig } 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: { contexts?: unknown }): {
41
- contexts: ContextConfig[];
42
- aliases: Record<string, string>;
43
- } {
44
- const contexts = normalizeContexts(config.contexts);
45
-
46
- const entries: Array<[string, string]> = [];
47
- for (const context of contexts) {
48
- entries.push([context.alias, `./src/app/${context.name}`]);
49
- }
50
-
51
- return {
52
- contexts,
53
- aliases: Object.fromEntries(entries)
54
- };
55
- }
56
-
57
- function parseAliasEntries(aliasBody: string): { ordered: string[]; map: Map<string, string> } {
58
- const entryRegex = /(['"`])([^'"`]+)\1\s*:\s*(['"`])([^'"`]+)\3\s*,?/g;
59
- const ordered: string[] = [];
60
- const map = new Map<string, string>();
61
- let match: RegExpExecArray | null;
62
-
63
- while ((match = entryRegex.exec(aliasBody)) !== null) {
64
- const key = match[2];
65
- const value = match[4];
66
- if (!key || !value) continue;
67
- if (!map.has(key)) {
68
- ordered.push(key);
69
- }
70
- map.set(key, value);
71
- }
72
-
73
- return { ordered, map };
74
- }
75
-
76
- function buildAliasEntriesString(orderedKeys: string[], map: Map<string, string>, baseIndent: string): string {
77
- if (!orderedKeys.length) return '';
78
-
79
- return orderedKeys.map((key) => `${baseIndent}'${key}': '${map.get(key) ?? ''}'`).join(',\n');
80
- }
81
-
82
- function removeAliasEntry(content: string, alias: string): string {
83
- const escapedAlias = alias.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
84
- const aliasRegex = new RegExp(`\\n?\\s*['"\`]${escapedAlias}['"\`]\\s*:\\s*['"\`][^'"\`]+['"\`]\\s*,?`, 'g');
85
- return content.replace(aliasRegex, '');
86
- }
87
-
88
- const removeCoreAliasFromAzureNetConfig = async (): Promise<void> => {
89
- const tsPath = path.resolve('azure-net.config.ts');
90
- const jsPath = path.resolve('azure-net.config.js');
91
- let filepath: string | null = null;
92
-
93
- try {
94
- await fs.access(tsPath);
95
- filepath = tsPath;
96
- } catch {
97
- try {
98
- await fs.access(jsPath);
99
- filepath = jsPath;
100
- } catch {
101
- return;
102
- }
103
- }
104
-
105
- const content = await fs.readFile(filepath, 'utf-8');
106
- if (!/coreAlias\s*:/.test(content)) return;
107
-
108
- const nextContent = content.replace(/\n?\s*coreAlias\s*:\s*['"`][^'"`]+['"`]\s*,?/m, '').replace(/,\s*\n\s*\}/m, '\n}');
109
- await fs.writeFile(filepath, nextContent, 'utf-8');
110
- };
111
-
112
- export function mergeAliasesInSvelteConfig(content: string, aliases: Record<string, string>): string {
113
- const aliasRegex = /alias\s*:\s*\{([\s\S]*?)\}/m;
114
- const aliasMatch = content.match(aliasRegex);
115
-
116
- if (aliasMatch) {
117
- const aliasBody = aliasMatch[1] ?? '';
118
- const { ordered, map } = parseAliasEntries(aliasBody);
119
- map.delete('$core');
120
- for (const [key, value] of Object.entries(aliases)) {
121
- if (!map.has(key)) ordered.push(key);
122
- map.set(key, value);
123
- }
124
- const nextOrdered = ordered.filter((key) => key !== '$core');
125
-
126
- const baseIndentMatch = aliasBody.match(/\n(\s*)['"`]/);
127
- const baseIndent = baseIndentMatch?.[1] ?? '\t\t\t';
128
- const merged = buildAliasEntriesString(nextOrdered, map, baseIndent);
129
- const nextAliasBlock = `alias: {\n${merged}\n\t\t}`;
130
- return content.replace(aliasRegex, nextAliasBlock);
131
- }
132
-
133
- const kitRegex = /kit\s*:\s*\{/m;
134
- if (kitRegex.test(content)) {
135
- const aliasLines = Object.entries(aliases)
136
- .map(([key, value]) => `\t\t\t'${key}': '${value}'`)
137
- .join(',\n');
138
- const aliasBlock = `alias: {\n${aliasLines}\n\t\t},`;
139
- return content.replace(kitRegex, `kit: {\n\t\t${aliasBlock}`);
140
- }
141
-
142
- return `${content}\n\n// azure-net aliases\nconst alias = {\n${Object.entries(aliases)
143
- .map(([key, value]) => `\t'${key}': '${value}'`)
144
- .join(',\n')}\n};\n`;
145
- }
146
-
147
- export default async function initAliases(): Promise<void> {
148
- const config = await loadUserConfig();
149
- const sharedAlias = String(config.sharedAlias ?? '').trim();
150
- if (!sharedAlias.length) {
151
- console.error('❌ Cannot update aliases: `sharedAlias` is missing in azure-net.config.ts/js.');
152
- console.error("Add it first, for example: sharedAlias: '$shared-kernel'");
153
- process.exitCode = 1;
154
- return;
155
- }
156
-
157
- const generated = generateAliases(config as { contexts?: unknown });
158
- const aliases = generated.aliases;
159
- await removeCoreAliasFromAzureNetConfig();
160
-
161
- let content: string;
162
- try {
163
- content = await fs.readFile(svelteConfigPath, 'utf-8');
164
- } catch {
165
- console.warn('⚠️ svelte.config.js not found, aliases were not updated');
166
- return;
167
- }
168
-
169
- const nextContent = removeAliasEntry(mergeAliasesInSvelteConfig(content, aliases), '$core');
170
- await fs.writeFile(svelteConfigPath, nextContent, 'utf-8');
171
- console.log('✅ Aliases updated in svelte.config.js');
172
- }