@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.
Files changed (180) hide show
  1. package/README.md +201 -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/presenterFactories.d.ts +9 -0
  44. package/dist/src/migrate/presenters.d.ts +13 -0
  45. package/dist/src/migrate/translations.d.ts +8 -0
  46. package/dist/src/plugins/addLint.d.ts +5 -0
  47. package/dist/src/scaffolds/createCoreSchema.d.ts +1 -0
  48. package/dist/src/scaffolds/createDatasource.d.ts +1 -0
  49. package/dist/src/scaffolds/createProgram.d.ts +1 -0
  50. package/dist/src/scaffolds/createResponse.d.ts +1 -0
  51. package/dist/src/scaffolds/createSchemaRule.d.ts +1 -0
  52. package/dist/src/scaffolds/createTranslationManager.d.ts +1 -0
  53. package/{src/scaffolds/index.ts → dist/src/scaffolds/index.d.ts} +0 -2
  54. package/dist/src/scaffolds/registerDatasource.d.ts +2 -0
  55. package/dist/src/scaffolds/updateDefaultFactoryConfig.d.ts +1 -0
  56. package/dist/src/utils/architecture.d.ts +31 -0
  57. package/dist/src/utils/contextUtils.d.ts +6 -0
  58. package/dist/src/utils/fileUtils.d.ts +5 -0
  59. package/dist/src/utils/flattenConfig.d.ts +2 -0
  60. package/dist/src/utils/legacyAliases.d.ts +1 -0
  61. package/dist/src/utils/loadConfig.d.ts +16 -0
  62. package/dist/src/utils/packageImports.d.ts +4 -0
  63. package/dist/src/utils/sharedFoundation.d.ts +20 -0
  64. package/dist/src/utils/viteConfig.d.ts +9 -0
  65. package/package.json +17 -7
  66. package/src/checks/architecture.js +154 -0
  67. package/src/checks/checkDomain.js +124 -154
  68. package/src/checks/checkFoldersStructure.js +64 -52
  69. package/src/checks/checkHooks.js +12 -12
  70. package/src/checks/checkImports.js +26 -142
  71. package/src/checks/checkInternal.js +27 -24
  72. package/src/checks/checkLayerBoundaries.js +22 -197
  73. package/src/checks/checkLayerImports.js +14 -134
  74. package/src/checks/checkPresenterNames.js +156 -143
  75. package/src/checks/checkProject.js +27 -26
  76. package/src/checks/checkProviderGraph.js +182 -166
  77. package/src/checks/checkProviderNames.js +123 -112
  78. package/src/generate/layers/generateRepository.js +1 -109
  79. package/src/generate/layers/generateRepositoryMethod.js +1 -90
  80. package/src/generate/layers/generateUseCases.js +1 -44
  81. package/src/generate/module/generateDomain.js +81 -105
  82. package/src/generate/module/generateModule.js +34 -68
  83. package/src/generate/module/generateModulePreset.js +188 -248
  84. package/src/generate/module/generatePresenter.js +441 -369
  85. package/src/generate/module/generateRepository.js +102 -121
  86. package/src/generate/module/generateRepositoryMethod.js +117 -0
  87. package/src/generate/module/generateSchemaFromType.js +283 -280
  88. package/src/generate/module/generateStore.js +41 -0
  89. package/src/generate/module/generateTypesJson.js +196 -195
  90. package/src/generate/module/generateUseCases.js +47 -55
  91. package/src/generate/module/repositoryModuleShared.js +480 -459
  92. package/src/generate/routes/generateRoutes.js +4 -7
  93. package/src/generate/ui/generateComponent.js +44 -64
  94. package/src/generate/ui/generateDesignComponent.js +21 -41
  95. package/src/generate/ui/generateWidget.js +21 -41
  96. package/src/git/commit.js +67 -0
  97. package/src/git/push.js +19 -0
  98. package/src/git/runGit.js +11 -0
  99. package/src/init/initAliases.js +19 -135
  100. package/src/init/initEdges.js +79 -54
  101. package/src/init/initStructure.js +31 -145
  102. package/src/install/configureCommitTools.js +1 -0
  103. package/src/install/installFresh.js +39 -68
  104. package/src/migrate/migrate.js +1027 -0
  105. package/src/migrate/presenterFactories.js +189 -0
  106. package/src/migrate/presenters.js +373 -0
  107. package/src/migrate/translations.js +213 -0
  108. package/src/plugins/addLint.js +52 -219
  109. package/src/scaffolds/createCoreSchema.js +65 -91
  110. package/src/scaffolds/createDatasource.js +67 -101
  111. package/src/scaffolds/createProgram.js +8 -8
  112. package/src/scaffolds/createResponse.js +29 -29
  113. package/src/scaffolds/createSchemaRule.js +19 -19
  114. package/src/scaffolds/createTranslationManager.js +84 -37
  115. package/src/scaffolds/index.js +0 -2
  116. package/src/scaffolds/registerDatasource.js +59 -0
  117. package/src/scaffolds/updateDefaultFactoryConfig.js +31 -0
  118. package/src/utils/architecture.js +145 -0
  119. package/src/utils/contextUtils.js +32 -65
  120. package/src/utils/fileUtils.js +69 -50
  121. package/src/utils/flattenConfig.js +38 -0
  122. package/src/utils/legacyAliases.js +75 -0
  123. package/src/utils/loadConfig.js +76 -40
  124. package/src/utils/packageImports.js +63 -0
  125. package/src/utils/sharedFoundation.js +36 -42
  126. package/src/utils/viteConfig.js +295 -0
  127. package/.prettierrc +0 -7
  128. package/bin/azure-net.ts +0 -308
  129. package/eslint.config.js +0 -34
  130. package/src/checks/checkDomain.ts +0 -223
  131. package/src/checks/checkFoldersStructure.ts +0 -85
  132. package/src/checks/checkHooks.ts +0 -22
  133. package/src/checks/checkImports.ts +0 -193
  134. package/src/checks/checkInternal.ts +0 -48
  135. package/src/checks/checkLayerBoundaries.ts +0 -255
  136. package/src/checks/checkLayerImports.ts +0 -185
  137. package/src/checks/checkPresenterNames.ts +0 -203
  138. package/src/checks/checkProject.ts +0 -45
  139. package/src/checks/checkProviderGraph.ts +0 -234
  140. package/src/checks/checkProviderNames.ts +0 -165
  141. package/src/generate/layers/generateRepository.ts +0 -123
  142. package/src/generate/layers/generateRepositoryMethod.ts +0 -102
  143. package/src/generate/layers/generateUseCases.ts +0 -50
  144. package/src/generate/layers/repositoryShared.js +0 -506
  145. package/src/generate/layers/repositoryShared.ts +0 -662
  146. package/src/generate/module/generateDomain.ts +0 -147
  147. package/src/generate/module/generateModule.ts +0 -84
  148. package/src/generate/module/generateModulePreset.ts +0 -338
  149. package/src/generate/module/generatePresenter.ts +0 -498
  150. package/src/generate/module/generateRepository.ts +0 -158
  151. package/src/generate/module/generateSchemaFromType.ts +0 -368
  152. package/src/generate/module/generateTypesJson.ts +0 -259
  153. package/src/generate/module/generateUseCases.ts +0 -67
  154. package/src/generate/module/repositoryModuleShared.ts +0 -669
  155. package/src/generate/routes/generateRoutes.ts +0 -275
  156. package/src/generate/ui/generateComponent.ts +0 -100
  157. package/src/generate/ui/generateDesignComponent.ts +0 -71
  158. package/src/generate/ui/generateWidget.ts +0 -71
  159. package/src/init/initAliases.ts +0 -172
  160. package/src/init/initEdges.ts +0 -74
  161. package/src/init/initStructure.ts +0 -172
  162. package/src/install/installFresh.ts +0 -93
  163. package/src/plugins/addLint.ts +0 -274
  164. package/src/scaffolds/createCoreSchema.ts +0 -130
  165. package/src/scaffolds/createDatasource.ts +0 -161
  166. package/src/scaffolds/createDatasourceProvider.js +0 -127
  167. package/src/scaffolds/createDatasourceProvider.ts +0 -161
  168. package/src/scaffolds/createPresenterFactory.js +0 -83
  169. package/src/scaffolds/createPresenterFactory.ts +0 -102
  170. package/src/scaffolds/createProgram.ts +0 -19
  171. package/src/scaffolds/createResponse.ts +0 -66
  172. package/src/scaffolds/createSchemaRule.ts +0 -44
  173. package/src/scaffolds/createTranslationManager.ts +0 -80
  174. package/src/utils/contextUtils.ts +0 -88
  175. package/src/utils/fileUtils.ts +0 -74
  176. package/src/utils/loadConfig.ts +0 -68
  177. package/src/utils/sharedFoundation.ts +0 -70
  178. package/tsconfig.json +0 -19
  179. /package/{src/checks/index.ts → dist/src/checks/index.d.ts} +0 -0
  180. /package/{src/plugins/index.ts → dist/src/plugins/index.d.ts} +0 -0
@@ -1,275 +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 type Route = (typeof routes)[number];');
216
- lines.push('');
217
-
218
- return `${lines.join('\n')}\n`;
219
- };
220
-
221
- const selectGroupingMode = async (): Promise<RouteGroupingMode | null> => {
222
- const { mode } = await prompts({
223
- type: 'select',
224
- name: 'mode',
225
- message: 'How should routes be grouped?',
226
- choices: [
227
- { title: 'By root route groups: (account), (landing), ...', value: 'root-groups' },
228
- { title: 'By azure-net.config.ts groupRoutesFunc', value: 'config-function' },
229
- { title: 'Do not group, generate one routes array', value: 'none' }
230
- ]
231
- });
232
-
233
- return mode ? (mode as RouteGroupingMode) : null;
234
- };
235
-
236
- const getConfigRouteGroupResolver = async (): Promise<RouteGroupResolver | null> => {
237
- const config = await loadUserConfig();
238
- if (typeof config.groupRoutesFunc !== 'function') {
239
- console.error('❌ `groupRoutesFunc` is missing in azure-net.config.ts/js or is not a function.');
240
- console.error('Example:');
241
- console.error('export default {');
242
- console.error("\tgroupRoutesFunc: (route) => route.rootGroup ?? 'app'");
243
- console.error('};');
244
- return null;
245
- }
246
-
247
- return config.groupRoutesFunc as RouteGroupResolver;
248
- };
249
-
250
- export default async function generateRoutes(): Promise<void> {
251
- const mode = await selectGroupingMode();
252
- if (!mode) return;
253
-
254
- const { sharedContext } = await getSharedState();
255
- const resolver = mode === 'config-function' ? await getConfigRouteGroupResolver() : undefined;
256
- if (mode === 'config-function' && !resolver) {
257
- process.exitCode = 1;
258
- return;
259
- }
260
-
261
- const routes = await collectRoutes(ROUTES_DIR);
262
- if (!routes.length) {
263
- console.warn('⚠️ No SvelteKit routes found in src/routes');
264
- return;
265
- }
266
-
267
- const groups = createGroupMap(routes, mode, resolver ?? undefined);
268
- const outputDir = path.join(getSharedContextRootPath(sharedContext.name), 'runtime', 'routes');
269
- const outputFile = path.join(outputDir, 'index.ts');
270
-
271
- await fs.mkdir(outputDir, { recursive: true });
272
- await fs.writeFile(outputFile, createGeneratedFile(groups), 'utf-8');
273
-
274
- console.log(`✅ Routes generated: ${outputFile}`);
275
- }
@@ -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
- }