@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
@@ -0,0 +1,265 @@
1
+ import ts from 'typescript';
2
+ import { parseSource } from '../checks/architecture.js';
3
+ const printer = ts.createPrinter();
4
+ const helperNames = new Set(['createAsyncAction', 'createAsyncResource']);
5
+ const apply = (input, edits) => {
6
+ for (const edit of edits.sort((a, b) => b.start - a.start))
7
+ input = input.slice(0, edit.start) + edit.text + input.slice(edit.end);
8
+ return input;
9
+ };
10
+ export function migrateAsyncHelpers(input, file) {
11
+ const source = parseSource(input, file);
12
+ const edits = [];
13
+ const factories = new Set();
14
+ const occupied = new Set();
15
+ const collect = (node) => {
16
+ if (ts.isIdentifier(node))
17
+ occupied.add(node.text);
18
+ ts.forEachChild(node, collect);
19
+ };
20
+ collect(source);
21
+ const unique = (base) => {
22
+ let name = base;
23
+ while (occupied.has(name))
24
+ name += '_';
25
+ occupied.add(name);
26
+ return name;
27
+ };
28
+ const action = unique('kitCreateAsyncAction');
29
+ const resource = unique('kitCreateAsyncResource');
30
+ let helpersImported = false;
31
+ for (const statement of source.statements) {
32
+ if (!ts.isImportDeclaration(statement) ||
33
+ !ts.isStringLiteral(statement.moduleSpecifier) ||
34
+ statement.moduleSpecifier.text !== '@azure-net/kit/delivery')
35
+ continue;
36
+ const bindings = statement.importClause?.namedBindings;
37
+ if (!bindings || !ts.isNamedImports(bindings))
38
+ continue;
39
+ const kept = bindings.elements.filter((entry) => {
40
+ if ((entry.propertyName ?? entry.name).text !== 'createAsyncHelpers')
41
+ return true;
42
+ factories.add(entry.name.text);
43
+ return false;
44
+ });
45
+ if (kept.length === bindings.elements.length)
46
+ continue;
47
+ const extra = helpersImported ? [] : [`createAsyncAction as ${action}`, `createAsyncResource as ${resource}`];
48
+ helpersImported = true;
49
+ edits.push({
50
+ start: bindings.getStart(source),
51
+ end: bindings.end,
52
+ text: `{ ${[...kept.map((e) => e.getText(source)), ...extra].join(', ')} }`
53
+ });
54
+ }
55
+ if (!factories.size)
56
+ return input;
57
+ const validate = (node) => {
58
+ if (ts.isImportDeclaration(node))
59
+ return;
60
+ if (ts.isIdentifier(node) && factories.has(node.text)) {
61
+ if (!ts.isCallExpression(node.parent) || node.parent.expression !== node || node.parent.arguments.length) {
62
+ throw new Error(`${node.text} is not a direct zero-argument call`);
63
+ }
64
+ }
65
+ ts.forEachChild(node, validate);
66
+ };
67
+ validate(source);
68
+ const specialize = (name, errorType) => errorType
69
+ ? `${name} as <Res = never, Req = never>(...args: Parameters<typeof ${name}<Res, Req, ${errorType}>>) => ReturnType<typeof ${name}<Res, Req, ${errorType}>>`
70
+ : name;
71
+ const visit = (node) => {
72
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && factories.has(node.expression.text) && !node.arguments.length) {
73
+ const errorType = node.typeArguments?.[0]?.getText(source);
74
+ edits.push({
75
+ start: node.getStart(source),
76
+ end: node.end,
77
+ text: `({ createAsyncAction: ${specialize(action, errorType)}, createAsyncResource: ${specialize(resource, errorType)} })`
78
+ });
79
+ return;
80
+ }
81
+ ts.forEachChild(node, visit);
82
+ };
83
+ visit(source);
84
+ return apply(input, edits);
85
+ }
86
+ /** Upgrade only recognized factories; arbitrary injected dependencies require a human decision. */
87
+ export function migratePresenterSource(input, file, factories) {
88
+ const source = ts.createSourceFile(file, input, ts.ScriptTarget.Latest, true);
89
+ const edits = [];
90
+ const converted = new Map();
91
+ const issues = [];
92
+ const imports = new Set();
93
+ const removedFactories = new Set();
94
+ const existingImports = new Set();
95
+ for (const statement of source.statements) {
96
+ if (!ts.isImportDeclaration(statement) ||
97
+ !ts.isStringLiteral(statement.moduleSpecifier) ||
98
+ statement.moduleSpecifier.text !== '@azure-net/kit/delivery' ||
99
+ statement.importClause?.isTypeOnly)
100
+ continue;
101
+ const bindings = statement.importClause?.namedBindings;
102
+ if (bindings && ts.isNamedImports(bindings))
103
+ for (const entry of bindings.elements) {
104
+ if (!entry.isTypeOnly)
105
+ existingImports.add(entry.propertyName ? `${entry.propertyName.text} as ${entry.name.text}` : entry.name.text);
106
+ }
107
+ }
108
+ for (const statement of source.statements) {
109
+ if (!ts.isVariableStatement(statement) || statement.declarationList.declarations.length !== 1)
110
+ continue;
111
+ const declaration = statement.declarationList.declarations[0];
112
+ const call = declaration.initializer;
113
+ if (!ts.isIdentifier(declaration.name) ||
114
+ !call ||
115
+ !ts.isCallExpression(call) ||
116
+ !ts.isIdentifier(call.expression) ||
117
+ !factories.has(call.expression.text))
118
+ continue;
119
+ const name = declaration.name.text;
120
+ try {
121
+ const callback = call.arguments.find((arg) => ts.isArrowFunction(arg) || ts.isFunctionExpression(arg));
122
+ if (!callback ||
123
+ (!ts.isArrowFunction(callback) && !ts.isFunctionExpression(callback)) ||
124
+ !ts.isBlock(callback.body) ||
125
+ callback.typeParameters ||
126
+ callback.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword))
127
+ throw new Error('Expected a synchronous block factory');
128
+ if (call.arguments.length !== 2 || !ts.isStringLiteral(call.arguments[0]))
129
+ throw new Error('Custom factory arguments need manual review');
130
+ const requestedImports = new Set();
131
+ if (callback.parameters.length) {
132
+ const param = callback.parameters[0];
133
+ if (callback.parameters.length !== 1 || !ts.isObjectBindingPattern(param.name) || param.initializer)
134
+ throw new Error('Unsupported injected dependencies');
135
+ for (const binding of param.name.elements) {
136
+ const original = (binding.propertyName ?? binding.name).getText(source);
137
+ if (!helperNames.has(original) || !ts.isIdentifier(binding.name) || binding.initializer || binding.dotDotDotToken)
138
+ throw new Error(`Injected dependency ${original} requires manual conversion`);
139
+ requestedImports.add(original === binding.name.text ? original : `${original} as ${binding.name.text}`);
140
+ }
141
+ }
142
+ const statements = [...callback.body.statements];
143
+ let usesThis = false;
144
+ const findThis = (node) => {
145
+ if (node.kind === ts.SyntaxKind.ThisKeyword)
146
+ usesThis = true;
147
+ ts.forEachChild(node, findThis);
148
+ };
149
+ findThis(callback.body);
150
+ if (usesThis)
151
+ throw new Error('Explicit this binding requires manual conversion');
152
+ const result = statements.at(-1);
153
+ if (!result || !ts.isReturnStatement(result) || !result.expression || !ts.isObjectLiteralExpression(result.expression))
154
+ throw new Error('Expected a final object-literal return');
155
+ const keys = result.expression.properties.map((prop) => {
156
+ if (!prop.name || !ts.isIdentifier(prop.name))
157
+ throw new Error('Spread/computed return keys require manual conversion');
158
+ if (prop.name.text === 'constructor')
159
+ throw new Error('Reserved presenter member');
160
+ return prop.name.text;
161
+ });
162
+ if (new Set(keys).size !== keys.length)
163
+ throw new Error('Duplicate return keys');
164
+ const parameters = [];
165
+ const argumentsList = [];
166
+ const registrations = [];
167
+ const body = statements.filter((stmt) => {
168
+ if (!ts.isVariableStatement(stmt) || stmt.declarationList.declarations.length !== 1)
169
+ return true;
170
+ const binding = stmt.declarationList.declarations[0];
171
+ const value = binding.initializer;
172
+ if (!ts.isObjectBindingPattern(binding.name) ||
173
+ !value ||
174
+ !ts.isCallExpression(value) ||
175
+ !ts.isIdentifier(value.expression) ||
176
+ !/Provider$/.test(value.expression.text))
177
+ return true;
178
+ if (value.arguments.length)
179
+ throw new Error('Provider arguments require manual conversion');
180
+ for (const entry of binding.name.elements) {
181
+ if (!ts.isIdentifier(entry.name) || entry.dotDotDotToken || entry.initializer)
182
+ throw new Error('Unsupported provider destructuring');
183
+ const key = (entry.propertyName ?? entry.name).getText(source).replace(/^['"]|['"]$/g, '');
184
+ parameters.push(`${entry.name.text}: ReturnType<typeof ${value.expression.text}>[${JSON.stringify(key)}]`);
185
+ argumentsList.push(entry.name.text);
186
+ }
187
+ registrations.push(stmt.getText(source));
188
+ return false;
189
+ });
190
+ // Keep lexical state and callbacks intact rather than guessing this-binding rewrites.
191
+ const setup = `create${name}State`;
192
+ if (new RegExp(`\\b(?:use${name}|${setup})\\b`).test(input))
193
+ throw new Error('Generated declaration name already exists');
194
+ const javascript = file.endsWith('.js');
195
+ const parameterList = (javascript ? argumentsList : parameters).join(', ');
196
+ const members = result.expression.properties.map((property, index) => {
197
+ const key = keys[index];
198
+ return (`get ${key}() { return this.#state.${key}; }` +
199
+ (ts.isGetAccessorDeclaration(property) || callback.type
200
+ ? ''
201
+ : `\nset ${key}(value${javascript ? '' : `: ReturnType<typeof ${setup}>[${JSON.stringify(key)}]`}) { this.#state.${key} = value; }`));
202
+ });
203
+ const text = `function ${setup}(${parameterList})${callback.type ? ': ' + callback.type.getText(source) : ''} {\n${body.map((stmt) => stmt.getText(source)).join('\n')}\n}\n\nexport class ${name} {\n#state${javascript ? '' : `: ReturnType<typeof ${setup}>`};\nconstructor(${parameterList}) { this.#state = ${setup}(${argumentsList.join(', ')}); }\n${members.join('\n')}\n}\n\nexport const use${name} = RegisterProvider(() => {\n${registrations.join('\n')}\nreturn new ${name}(${argumentsList.join(', ')});\n}, 'scoped');`;
204
+ edits.push({ start: statement.getStart(source), end: statement.end, text });
205
+ converted.set(name, `use${name}`);
206
+ removedFactories.add(call.expression.text);
207
+ imports.add('RegisterProvider');
208
+ for (const helper of requestedImports)
209
+ imports.add(helper);
210
+ }
211
+ catch (error) {
212
+ issues.push(`${name}: ${String(error)}. Original presenter retained.`);
213
+ }
214
+ }
215
+ let output = apply(input, edits);
216
+ if (converted.size) {
217
+ const parsed = ts.createSourceFile(file, output, ts.ScriptTarget.Latest, true);
218
+ const importEdits = [];
219
+ for (const statement of parsed.statements) {
220
+ if (!ts.isImportDeclaration(statement) ||
221
+ !statement.importClause?.namedBindings ||
222
+ !ts.isNamedImports(statement.importClause.namedBindings))
223
+ continue;
224
+ const bindings = statement.importClause.namedBindings;
225
+ const kept = bindings.elements.filter((entry) => {
226
+ if (!removedFactories.has(entry.name.text))
227
+ return true;
228
+ let used = false;
229
+ const visit = (node) => {
230
+ if (ts.isImportDeclaration(node))
231
+ return;
232
+ if (ts.isIdentifier(node) && node.text === entry.name.text)
233
+ used = true;
234
+ ts.forEachChild(node, visit);
235
+ };
236
+ visit(parsed);
237
+ return used;
238
+ });
239
+ if (kept.length === bindings.elements.length)
240
+ continue;
241
+ const updated = kept.length || statement.importClause.name
242
+ ? ts.factory.updateImportDeclaration(statement, statement.modifiers, ts.factory.updateImportClause(statement.importClause, statement.importClause.isTypeOnly, statement.importClause.name, kept.length ? ts.factory.updateNamedImports(bindings, kept) : undefined), statement.moduleSpecifier, statement.attributes)
243
+ : undefined;
244
+ importEdits.push({
245
+ start: statement.getStart(parsed),
246
+ end: statement.end,
247
+ text: updated ? printer.printNode(ts.EmitHint.Unspecified, updated, parsed) : ''
248
+ });
249
+ }
250
+ const neededImports = [...imports].filter((name) => !existingImports.has(name));
251
+ output =
252
+ (neededImports.length ? `import { ${neededImports.join(', ')} } from '@azure-net/kit/delivery';\n` : '') + apply(output, importEdits);
253
+ const updated = ts.createSourceFile(file, output, ts.ScriptTarget.Latest, true);
254
+ const references = [];
255
+ const visit = (node) => {
256
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && converted.has(node.expression.text)) {
257
+ references.push({ start: node.expression.getStart(updated), end: node.expression.end, text: converted.get(node.expression.text) });
258
+ }
259
+ ts.forEachChild(node, visit);
260
+ };
261
+ visit(updated);
262
+ output = apply(output, references);
263
+ }
264
+ return { content: output, converted, issues };
265
+ }
@@ -1,222 +1,55 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { execSync } from 'node:child_process';
4
- const dependencies = ['@commitlint/cli', 'semantic-release', '@semantic-release/git', 'git-cz', 'husky', 'commitizen', 'env-cmd'];
5
- const commitlintConfig = `export default {
6
- rules: {
7
- 'body-leading-blank': [2, 'always'],
8
- 'footer-leading-blank': [2, 'always'],
9
- 'header-max-length': [2, 'always', 72],
10
- 'subject-empty': [2, 'never'],
11
- 'subject-full-stop': [2, 'never', '.'],
12
- 'type-case': [2, 'always', 'lower-case'],
13
- 'type-empty': [2, 'never'],
14
- 'type-enum': [2, 'always', ['feat', 'fix', 'refactor', 'perf', 'chore', 'docs', 'style', 'test', 'ci']]
15
- }
16
- };
17
- `;
18
- const releaseConfig = `export default {
19
- branches: ['main', 'dev'],
20
- dryRun: false,
21
- ci: false,
22
- plugins: [
23
- [
24
- '@semantic-release/commit-analyzer',
25
- {
26
- releaseRules: [
27
- { type: 'release', release: 'major' },
28
- { type: 'feature', release: 'minor' },
29
- { type: 'perf', release: false },
30
- { type: 'refactor', release: false },
31
- { type: 'fix', release: 'patch' },
32
- { type: 'chore', release: false },
33
- { type: 'ci', release: false },
34
- { type: 'docs', scope: 'README', release: false },
35
- { type: 'test', release: false },
36
- { type: 'style', release: false }
37
- ]
38
- }
39
- ],
40
- '@semantic-release/release-notes-generator'
41
- ]
42
- };
43
- `;
44
- const prettierConfig = `{
45
- "useTabs": true,
46
- "singleQuote": true,
47
- "trailingComma": "none",
48
- "tabWidth": 2,
49
- "semi": true,
50
- "printWidth": 150,
51
- "plugins": ["prettier-plugin-svelte"],
52
- "overrides": [
53
- {
54
- "files": "*.svelte",
55
- "options": {
56
- "parser": "svelte"
57
- }
58
- }
59
- ]
60
- }
61
- `;
62
- const resolveInstallCommand = (manager) => {
63
- const deps = dependencies.join(' ');
64
- switch (manager) {
65
- case 'pnpm':
66
- return `pnpm add -D ${deps}`;
67
- case 'npm':
68
- return `npm install -D ${deps}`;
69
- case 'yarn':
70
- return `yarn add -D ${deps}`;
71
- case 'bun':
72
- return `bun add -d ${deps}`;
73
- }
74
- };
75
- const resolveRunScriptCommand = (manager, script) => {
76
- switch (manager) {
77
- case 'pnpm':
78
- return `pnpm ${script}`;
79
- case 'npm':
80
- return `npm run ${script}`;
81
- case 'yarn':
82
- return `yarn ${script}`;
83
- case 'bun':
84
- return `bun run ${script}`;
85
- }
86
- };
87
- const resolveHuskyCommand = (manager) => {
88
- switch (manager) {
89
- case 'pnpm':
90
- return 'pnpm exec husky';
91
- case 'npm':
92
- return 'npx husky';
93
- case 'yarn':
94
- return 'yarn husky';
95
- case 'bun':
96
- return 'bunx husky';
97
- }
98
- };
99
- const detectPackageManager = (cwd) => {
100
- if (fs.existsSync(path.join(cwd, 'bun.lock')) || fs.existsSync(path.join(cwd, 'bun.lockb'))) return 'bun';
101
- if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) return 'pnpm';
102
- if (fs.existsSync(path.join(cwd, 'yarn.lock'))) return 'yarn';
103
- if (fs.existsSync(path.join(cwd, 'package-lock.json'))) return 'npm';
104
- return undefined;
105
- };
106
- const parseConfigState = (cwd) => {
107
- const tsPath = path.join(cwd, 'azure-net.config.ts');
108
- const jsPath = path.join(cwd, 'azure-net.config.js');
109
- const configPath = fs.existsSync(tsPath) ? tsPath : fs.existsSync(jsPath) ? jsPath : null;
110
- if (!configPath) {
111
- return {
112
- configPath: null,
113
- content: null,
114
- hasPackageManagerKey: false,
115
- validPackageManager: null
116
- };
117
- }
118
- const content = fs.readFileSync(configPath, 'utf-8');
119
- const hasPackageManagerKey = /packageManager\s*:/.test(content);
120
- const managerMatch = content.match(/packageManager\s*:\s*['"`](bun|pnpm|npm|yarn)['"`]/);
121
- const validPackageManager = managerMatch?.[1];
122
- return {
123
- configPath,
124
- content,
125
- hasPackageManagerKey,
126
- validPackageManager: validPackageManager ?? null
127
- };
128
- };
129
- const upsertPackageManagerInConfig = (content, manager) => {
130
- const packageManagerEntry = `packageManager: '${manager}'`;
131
- const hasExportDefaultObject = /export\s+default\s*\{[\s\S]*\}\s*;?/.test(content);
132
- if (!hasExportDefaultObject) {
133
- return `export default {\n\t${packageManagerEntry}\n};\n`;
134
- }
135
- if (/packageManager\s*:/.test(content)) {
136
- return content.replace(/packageManager\s*:\s*['"`][^'"`]+['"`]/, packageManagerEntry);
137
- }
138
- return content.replace(/export\s+default\s*\{([\s\S]*?)\}\s*;?/, (_full, body) => {
139
- const trimmedRight = body.replace(/\s*$/, '');
140
- if (!trimmedRight.length) {
141
- return `export default {\n\t${packageManagerEntry}\n};`;
142
- }
143
- const withComma = trimmedRight.endsWith(',') ? trimmedRight : `${trimmedRight},`;
144
- return `export default {${withComma}\n\t${packageManagerEntry}\n};`;
145
- });
146
- };
147
- const localOnlyPrepareScript = `node -e "const local = !process.env.CI && process.env.NODE_ENV !== 'production' && !process.env.DOCKER && !process.env.CONTAINER; process.exit(local ? 1 : 0)" || (husky && svelte-kit sync)`;
148
- const selectPackageManager = async (cwd, preset) => {
149
- if (preset) return preset;
150
- const { default: prompts } = await import('prompts');
151
- const detected = detectPackageManager(cwd);
152
- const response = await prompts({
153
- type: 'select',
154
- name: 'manager',
155
- message: 'Choose your package manager:',
156
- choices: [
157
- { title: 'bun', value: 'bun' },
158
- { title: 'pnpm', value: 'pnpm' },
159
- { title: 'npm', value: 'npm' },
160
- { title: 'yarn', value: 'yarn' }
161
- ],
162
- initial: detected ? ['bun', 'pnpm', 'npm', 'yarn'].indexOf(detected) : 0
163
- });
164
- if (!response.manager) {
165
- throw new Error('Package manager is required');
166
- }
167
- return response.manager;
168
- };
169
- export default async function addLint(options = {}) {
170
- const cwd = process.cwd();
171
- const pkgPath = path.join(cwd, 'package.json');
172
- if (!fs.existsSync(pkgPath)) {
173
- console.error('❌ package.json not found in this directory');
174
- process.exit(1);
175
- }
176
- const configState = parseConfigState(cwd);
177
- const manager = configState.validPackageManager ?? (await selectPackageManager(cwd, options.manager));
178
- if (!configState.configPath) {
179
- const newConfigPath = path.join(cwd, 'azure-net.config.ts');
180
- fs.writeFileSync(newConfigPath, `export default {\n\tpackageManager: '${manager}'\n};\n`);
181
- } else if (!configState.validPackageManager || !configState.hasPackageManagerKey) {
182
- const nextConfig = upsertPackageManagerInConfig(configState.content ?? '', manager);
183
- fs.writeFileSync(configState.configPath, nextConfig);
184
- }
185
- const installCommand = resolveInstallCommand(manager);
186
- const runFormatCommand = resolveRunScriptCommand(manager, 'format');
187
- const preCommitScript = `${resolveRunScriptCommand(manager, 'lint')} && ${resolveRunScriptCommand(manager, 'check')}`;
188
- const commitScript = `${resolveRunScriptCommand(manager, 'format')} && git add . && git-cz && git push`;
189
- const releaseScript = `${resolveRunScriptCommand(manager, 'commit')} && ${resolveRunScriptCommand(manager, 'semantic-release')}`;
190
- console.log(`📦 Installing packages with ${manager}...`);
191
- execSync(installCommand, { stdio: 'inherit' });
192
- console.log('📁 Updating package.json...');
193
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
194
- pkg.scripts = {
195
- ...(pkg.scripts ?? {}),
196
- precommit: preCommitScript,
197
- prepare: localOnlyPrepareScript,
198
- 'semantic-release': 'env-cmd semantic-release',
199
- commit: commitScript,
200
- release: releaseScript
201
- };
202
- pkg.config = pkg.config ?? {};
203
- pkg.config.commitizen = {
204
- path: 'git-cz'
205
- };
206
- fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 4));
207
- fs.writeFileSync(path.join(cwd, 'commitlint.config.ts'), commitlintConfig);
208
- fs.writeFileSync(path.join(cwd, 'release.config.ts'), releaseConfig);
209
- fs.writeFileSync(path.join(cwd, '.prettierrc'), prettierConfig);
210
- console.log('🔧 Initializing Husky...');
211
- try {
212
- execSync(resolveHuskyCommand(manager), { stdio: 'inherit' });
213
- } catch {
214
- console.warn('⚠️ Husky initialization skipped (command failed in current environment).');
215
- }
216
- try {
217
- execSync(runFormatCommand, { stdio: 'inherit' });
218
- } catch {
219
- console.warn('⚠️ Format script execution skipped (script may be missing).');
220
- }
221
- console.log(`✅ Linting and release setup completed! Added prepare script: ${localOnlyPrepareScript}`);
3
+ export default async function addLint(_options = {}) {
4
+ // Retain compatibility with the existing --manager option without running a package manager.
5
+ void _options;
6
+ const cwd = process.cwd();
7
+ const pkgPath = path.join(cwd, 'package.json');
8
+ if (!fs.existsSync(pkgPath))
9
+ throw new Error('package.json not found in this directory');
10
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
11
+ const configNames = [
12
+ '.prettierrc',
13
+ '.prettierrc.json',
14
+ '.prettierrc.json5',
15
+ '.prettierrc.yaml',
16
+ '.prettierrc.yml',
17
+ '.prettierrc.toml',
18
+ '.prettierrc.js',
19
+ '.prettierrc.cjs',
20
+ '.prettierrc.mjs',
21
+ '.prettierrc.ts',
22
+ '.prettierrc.cts',
23
+ '.prettierrc.mts',
24
+ 'prettier.config.js',
25
+ 'prettier.config.cjs',
26
+ 'prettier.config.mjs',
27
+ 'prettier.config.ts',
28
+ 'prettier.config.cts',
29
+ 'prettier.config.mts'
30
+ ];
31
+ const existingConfigs = configNames.filter((name) => fs.existsSync(path.join(cwd, name)));
32
+ if ('prettier' in pkg || existingConfigs.length) {
33
+ const backupRoot = path.join(cwd, '.azure-net', 'PrettierBackups');
34
+ fs.mkdirSync(backupRoot, { recursive: true });
35
+ // Atomic directory creation prevents overwriting backups from rapid repeated runs.
36
+ const backup = fs.mkdtempSync(path.join(backupRoot, 'config-'));
37
+ if ('prettier' in pkg) {
38
+ fs.copyFileSync(pkgPath, path.join(backup, 'package.json'), fs.constants.COPYFILE_EXCL);
39
+ delete pkg.prettier;
40
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, '\t') + '\n');
41
+ }
42
+ for (const name of existingConfigs) {
43
+ fs.renameSync(path.join(cwd, name), path.join(backup, name));
44
+ }
45
+ }
46
+ fs.writeFileSync(path.join(cwd, '.prettierrc'), JSON.stringify({
47
+ useTabs: true,
48
+ singleQuote: true,
49
+ trailingComma: 'none',
50
+ tabWidth: 2,
51
+ semi: true,
52
+ printWidth: 150
53
+ }, null, '\t') + '\n');
54
+ console.log('Prettier configuration replaced. No packages installed.');
222
55
  }