@adonisjs/assembler 8.0.0-next.27 → 8.0.0-next.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/codemod_exception-vyN1VXuX.js +137 -0
- package/build/index.d.ts +1 -0
- package/build/index.js +2 -1
- package/build/src/code_transformer/main.d.ts +9 -0
- package/build/src/code_transformer/main.js +106 -27
- package/build/src/code_transformer/rc_file_transformer.d.ts +28 -2
- package/build/src/exceptions/codemod_exception.d.ts +178 -0
- package/build/src/types/code_transformer.d.ts +8 -0
- package/package.json +11 -11
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
var CodemodException = class CodemodException extends Error {
|
|
2
|
+
instructions;
|
|
3
|
+
filePath;
|
|
4
|
+
constructor(message, options) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "CodemodException";
|
|
7
|
+
this.instructions = options?.instructions;
|
|
8
|
+
this.filePath = options?.filePath;
|
|
9
|
+
}
|
|
10
|
+
static #formatEnvValidations(definition) {
|
|
11
|
+
const lines = [];
|
|
12
|
+
if (definition.leadingComment) {
|
|
13
|
+
lines.push(`/*`);
|
|
14
|
+
lines.push(`|----------------------------------------------------------`);
|
|
15
|
+
lines.push(`| ${definition.leadingComment}`);
|
|
16
|
+
lines.push(`|----------------------------------------------------------`);
|
|
17
|
+
lines.push(`*/`);
|
|
18
|
+
}
|
|
19
|
+
for (const [variable, validation] of Object.entries(definition.variables)) lines.push(`${variable}: ${validation},`);
|
|
20
|
+
return lines.join("\n");
|
|
21
|
+
}
|
|
22
|
+
static #formatMiddleware(stack, middleware) {
|
|
23
|
+
if (stack === "named") return `export const middleware = router.named({\n ${middleware.filter((m) => m.name).map((m) => `${m.name}: () => import('${m.path}')`).join(",\n ")}\n})`;
|
|
24
|
+
return `${stack}.use([\n ${middleware.map((m) => `() => import('${m.path}')`).join(",\n ")}\n])`;
|
|
25
|
+
}
|
|
26
|
+
static #formatPolicies(policies) {
|
|
27
|
+
return `export const policies = {\n ${policies.map((p) => `${p.name}: () => import('${p.path}')`).join(",\n ")}\n}`;
|
|
28
|
+
}
|
|
29
|
+
static #formatVitePlugin(pluginCall, importDeclarations) {
|
|
30
|
+
return `${importDeclarations.map((decl) => decl.isNamed ? `import { ${decl.identifier} } from '${decl.module}'` : `import ${decl.identifier} from '${decl.module}'`).join("\n")}\n\nexport default defineConfig({\n plugins: [${pluginCall}]\n})`;
|
|
31
|
+
}
|
|
32
|
+
static #formatJapaPlugin(pluginCall, importDeclarations) {
|
|
33
|
+
return `${importDeclarations.map((decl) => decl.isNamed ? `import { ${decl.identifier} } from '${decl.module}'` : `import ${decl.identifier} from '${decl.module}'`).join("\n")}\n\nexport const plugins: Config['plugins'] = [\n ${pluginCall}\n]`;
|
|
34
|
+
}
|
|
35
|
+
static missingEnvFile(filePath, definition) {
|
|
36
|
+
const code = this.#formatEnvValidations(definition);
|
|
37
|
+
return new CodemodException(`Could not find source file at path: "${filePath}"`, {
|
|
38
|
+
filePath,
|
|
39
|
+
instructions: `Add the following code to "${filePath}":\n\n${code}`
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
static missingEnvCreate(filePath, definition) {
|
|
43
|
+
return new CodemodException(`Cannot find Env.create statement in the file.`, {
|
|
44
|
+
filePath,
|
|
45
|
+
instructions: `Add the following code inside Env.create() in "${filePath}":\n\n${this.#formatEnvValidations(definition)}`
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
static invalidEnvCreate(filePath, definition) {
|
|
49
|
+
return new CodemodException(`The second argument of Env.create is not an object literal.`, {
|
|
50
|
+
filePath,
|
|
51
|
+
instructions: `Add the following code inside Env.create() in "${filePath}":\n\n${this.#formatEnvValidations(definition)}`
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
static missingKernelFile(filePath, stack, middleware) {
|
|
55
|
+
const code = this.#formatMiddleware(stack, middleware);
|
|
56
|
+
return new CodemodException(`Could not find source file at path: "${filePath}"`, {
|
|
57
|
+
filePath,
|
|
58
|
+
instructions: `Add the following code to "${filePath}":\n\n${code}`
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
static missingMiddlewareStack(filePath, stack, middleware) {
|
|
62
|
+
const code = this.#formatMiddleware(stack, middleware);
|
|
63
|
+
return new CodemodException(`Cannot find ${stack === "named" ? "middleware variable" : `${stack}.use`} statement in the file.`, {
|
|
64
|
+
filePath,
|
|
65
|
+
instructions: `Add the following code to "${filePath}":\n\n${code}`
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
static invalidMiddlewareStack(filePath, stack, middleware, reason) {
|
|
69
|
+
return new CodemodException(reason, {
|
|
70
|
+
filePath,
|
|
71
|
+
instructions: `Add the following code to "${filePath}":\n\n${this.#formatMiddleware(stack, middleware)}`
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
static missingPoliciesFile(filePath, policies) {
|
|
75
|
+
const code = this.#formatPolicies(policies);
|
|
76
|
+
return new CodemodException(`Could not find source file at path: "${filePath}"`, {
|
|
77
|
+
filePath,
|
|
78
|
+
instructions: `Add the following code to "${filePath}":\n\n${code}`
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
static invalidPoliciesFile(filePath, policies, reason) {
|
|
82
|
+
return new CodemodException(reason, {
|
|
83
|
+
filePath,
|
|
84
|
+
instructions: `Add the following code to "${filePath}":\n\n${this.#formatPolicies(policies)}`
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
static missingViteConfig(filePath, pluginCall, importDeclarations) {
|
|
88
|
+
return new CodemodException(`Cannot find vite.config.ts file. Make sure to rename vite.config.js to vite.config.ts`, {
|
|
89
|
+
filePath,
|
|
90
|
+
instructions: `Add the following code to "${filePath}":\n\n${this.#formatVitePlugin(pluginCall, importDeclarations)}`
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
static invalidViteConfig(filePath, pluginCall, importDeclarations, reason) {
|
|
94
|
+
return new CodemodException(reason, {
|
|
95
|
+
filePath,
|
|
96
|
+
instructions: `Add the following code to "${filePath}":\n\n${this.#formatVitePlugin(pluginCall, importDeclarations)}`
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
static missingJapaBootstrap(filePath, pluginCall, importDeclarations) {
|
|
100
|
+
const code = this.#formatJapaPlugin(pluginCall, importDeclarations);
|
|
101
|
+
return new CodemodException(`Could not find source file at path: "${filePath}"`, {
|
|
102
|
+
filePath,
|
|
103
|
+
instructions: `Add the following code to "${filePath}":\n\n${code}`
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
static invalidJapaBootstrap(filePath, pluginCall, importDeclarations, reason) {
|
|
107
|
+
return new CodemodException(reason, {
|
|
108
|
+
filePath,
|
|
109
|
+
instructions: `Add the following code to "${filePath}":\n\n${this.#formatJapaPlugin(pluginCall, importDeclarations)}`
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
static missingRcFile(filePath, codeToAdd) {
|
|
113
|
+
return new CodemodException(`Could not find source file at path: "${filePath}"`, {
|
|
114
|
+
filePath,
|
|
115
|
+
instructions: `Add the following code to "${filePath}":\n\n${codeToAdd}`
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
static invalidRcFile(filePath, codeToAdd, reason) {
|
|
119
|
+
return new CodemodException(reason, {
|
|
120
|
+
filePath,
|
|
121
|
+
instructions: `Add the following code to "${filePath}":\n\n${codeToAdd}`
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
static E_CODEMOD_FILE_NOT_FOUND(filePath, codeToAdd) {
|
|
125
|
+
return new CodemodException(`Could not find source file at path: "${filePath}"`, {
|
|
126
|
+
filePath,
|
|
127
|
+
instructions: `Add the following code to "${filePath}":\n\n${codeToAdd}`
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
static E_CODEMOD_INVALID_STRUCTURE(message, filePath, codeToAdd) {
|
|
131
|
+
return new CodemodException(message, {
|
|
132
|
+
filePath,
|
|
133
|
+
instructions: `Add the following code to "${filePath}":\n\n${codeToAdd}`
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
export { CodemodException as t };
|
package/build/index.d.ts
CHANGED
|
@@ -3,4 +3,5 @@ export { DevServer } from './src/dev_server.ts';
|
|
|
3
3
|
export { TestRunner } from './src/test_runner.ts';
|
|
4
4
|
export { FileBuffer } from './src/file_buffer.ts';
|
|
5
5
|
export { VirtualFileSystem } from './src/virtual_file_system.ts';
|
|
6
|
+
export { CodemodException } from './src/exceptions/codemod_exception.ts';
|
|
6
7
|
export { SUPPORTED_PACKAGE_MANAGERS } from './src/bundler.ts';
|
package/build/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { a as loadHooks, c as readTsConfig, d as runNode, f as throttle, m as de
|
|
|
2
2
|
import { n as FileBuffer, t as IndexGenerator } from "./main-XUXlmlEy.js";
|
|
3
3
|
import { t as RoutesScanner } from "./main-BeV45LeF.js";
|
|
4
4
|
import "./helpers-DDurYRsZ.js";
|
|
5
|
+
import { t as CodemodException } from "./codemod_exception-vyN1VXuX.js";
|
|
5
6
|
import dedent from "dedent";
|
|
6
7
|
import fs, { readFile, unlink } from "node:fs/promises";
|
|
7
8
|
import { cliui } from "@poppinss/cliui";
|
|
@@ -934,4 +935,4 @@ var TestRunner = class {
|
|
|
934
935
|
});
|
|
935
936
|
}
|
|
936
937
|
};
|
|
937
|
-
export { Bundler, DevServer, FileBuffer, SUPPORTED_PACKAGE_MANAGERS, TestRunner, VirtualFileSystem };
|
|
938
|
+
export { Bundler, CodemodException, DevServer, FileBuffer, SUPPORTED_PACKAGE_MANAGERS, TestRunner, VirtualFileSystem };
|
|
@@ -39,6 +39,15 @@ export declare class CodeTransformer {
|
|
|
39
39
|
* @param cwd - The current working directory URL
|
|
40
40
|
*/
|
|
41
41
|
constructor(cwd: URL);
|
|
42
|
+
/**
|
|
43
|
+
* Get directories configured in adonisrc.ts, with defaults fallback.
|
|
44
|
+
*
|
|
45
|
+
* This method reads the adonisrc.ts file and extracts the directories
|
|
46
|
+
* configuration. If a directory is not configured, the default value is used.
|
|
47
|
+
*
|
|
48
|
+
* @returns Object containing directory paths
|
|
49
|
+
*/
|
|
50
|
+
getDirectories(): Record<string, string>;
|
|
42
51
|
/**
|
|
43
52
|
* Add new env variable validation in the `env.ts` file
|
|
44
53
|
*
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as CodemodException } from "../../codemod_exception-vyN1VXuX.js";
|
|
1
2
|
import { fileURLToPath } from "node:url";
|
|
2
3
|
import { detectPackageManager, installPackage } from "@antfu/install-pkg";
|
|
3
4
|
import { join } from "node:path";
|
|
@@ -24,8 +25,15 @@ var RcFileTransformer = class {
|
|
|
24
25
|
this.#project = project;
|
|
25
26
|
}
|
|
26
27
|
#getRcFileOrThrow() {
|
|
27
|
-
const
|
|
28
|
-
|
|
28
|
+
const filePath = "adonisrc.ts";
|
|
29
|
+
const rcFileUrl = fileURLToPath(new URL(`./${filePath}`, this.#cwd));
|
|
30
|
+
const file = this.#project.getSourceFile(rcFileUrl);
|
|
31
|
+
if (!file) throw CodemodException.missingRcFile(filePath, `import { defineConfig } from '@adonisjs/core/app'
|
|
32
|
+
|
|
33
|
+
export default defineConfig({
|
|
34
|
+
// Add your configuration here
|
|
35
|
+
})`);
|
|
36
|
+
return file;
|
|
29
37
|
}
|
|
30
38
|
#isInSpecificEnvironment(environments) {
|
|
31
39
|
if (!environments) return false;
|
|
@@ -33,7 +41,11 @@ var RcFileTransformer = class {
|
|
|
33
41
|
}
|
|
34
42
|
#locateDefineConfigCallOrThrow(file) {
|
|
35
43
|
const call = file.getDescendantsOfKind(SyntaxKind.CallExpression).find((statement) => statement.getExpression().getText() === "defineConfig");
|
|
36
|
-
if (!call) throw
|
|
44
|
+
if (!call) throw CodemodException.invalidRcFile("adonisrc.ts", `import { defineConfig } from '@adonisjs/core/app'
|
|
45
|
+
|
|
46
|
+
export default defineConfig({
|
|
47
|
+
// Add your configuration here
|
|
48
|
+
})`, "Could not locate the defineConfig call.");
|
|
37
49
|
return call;
|
|
38
50
|
}
|
|
39
51
|
#getDefineConfigObjectOrThrow(defineConfigCall) {
|
|
@@ -127,7 +139,7 @@ var RcFileTransformer = class {
|
|
|
127
139
|
}`);
|
|
128
140
|
return this;
|
|
129
141
|
}
|
|
130
|
-
addAssemblerHook(type,
|
|
142
|
+
addAssemblerHook(type, value, raw = false) {
|
|
131
143
|
const hooks = this.#getPropertyAssignmentInDefineConfigCall("hooks", "{}").getInitializerIfKindOrThrow(SyntaxKind.ObjectLiteralExpression);
|
|
132
144
|
let hookArray = hooks.getProperty(type);
|
|
133
145
|
if (!hookArray) {
|
|
@@ -138,10 +150,44 @@ var RcFileTransformer = class {
|
|
|
138
150
|
hookArray = hooks.getProperty(type);
|
|
139
151
|
}
|
|
140
152
|
const hooksArray = hookArray.getInitializerIfKindOrThrow(SyntaxKind.ArrayLiteralExpression);
|
|
141
|
-
if (
|
|
142
|
-
|
|
153
|
+
if (raw) hooksArray.addElement(value);
|
|
154
|
+
else {
|
|
155
|
+
if (this.#extractModulesFromArray(hooksArray).includes(value)) return this;
|
|
156
|
+
hooksArray.addElement(`() => import('${value}')`);
|
|
157
|
+
}
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
addNamedImport(specifier, names) {
|
|
161
|
+
this.#getRcFileOrThrow().addImportDeclaration({
|
|
162
|
+
moduleSpecifier: specifier,
|
|
163
|
+
namedImports: names
|
|
164
|
+
});
|
|
143
165
|
return this;
|
|
144
166
|
}
|
|
167
|
+
addDefaultImport(specifier, name) {
|
|
168
|
+
this.#getRcFileOrThrow().addImportDeclaration({
|
|
169
|
+
moduleSpecifier: specifier,
|
|
170
|
+
defaultImport: name
|
|
171
|
+
});
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
getDirectory(key, defaultValue) {
|
|
175
|
+
try {
|
|
176
|
+
const file = this.#getRcFileOrThrow();
|
|
177
|
+
const defineConfigCall = this.#locateDefineConfigCallOrThrow(file);
|
|
178
|
+
const directoriesProperty = this.#getDefineConfigObjectOrThrow(defineConfigCall).getProperty("directories");
|
|
179
|
+
if (!directoriesProperty || !Node.isPropertyAssignment(directoriesProperty)) return defaultValue;
|
|
180
|
+
const directoriesObject = directoriesProperty.getInitializer();
|
|
181
|
+
if (!directoriesObject || !Node.isObjectLiteralExpression(directoriesObject)) return defaultValue;
|
|
182
|
+
const property = directoriesObject.getProperty(key);
|
|
183
|
+
if (!property || !Node.isPropertyAssignment(property)) return defaultValue;
|
|
184
|
+
const initializer = property.getInitializer();
|
|
185
|
+
if (!initializer || !Node.isStringLiteral(initializer)) return defaultValue;
|
|
186
|
+
return initializer.getLiteralValue();
|
|
187
|
+
} catch {
|
|
188
|
+
return defaultValue;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
145
191
|
save() {
|
|
146
192
|
const file = this.#getRcFileOrThrow();
|
|
147
193
|
file.formatText(this.#editorSettings);
|
|
@@ -170,6 +216,14 @@ var CodeTransformer = class {
|
|
|
170
216
|
manipulationSettings: { quoteKind: QuoteKind.Single }
|
|
171
217
|
});
|
|
172
218
|
}
|
|
219
|
+
getDirectories() {
|
|
220
|
+
const rcFileTransformer = new RcFileTransformer(this.#cwd, this.project);
|
|
221
|
+
return {
|
|
222
|
+
start: rcFileTransformer.getDirectory("start", "start"),
|
|
223
|
+
tests: rcFileTransformer.getDirectory("tests", "tests"),
|
|
224
|
+
policies: rcFileTransformer.getDirectory("policies", "app/policies")
|
|
225
|
+
};
|
|
226
|
+
}
|
|
173
227
|
#addToMiddlewareArray(file, target, middlewareEntry) {
|
|
174
228
|
const callExpressions = file.getDescendantsOfKind(SyntaxKind.CallExpression).filter((statement) => statement.getExpression().getText() === target);
|
|
175
229
|
if (!callExpressions.length) throw new Error(`Cannot find ${target} statement in the file.`);
|
|
@@ -217,12 +271,14 @@ var CodeTransformer = class {
|
|
|
217
271
|
return writer.blankLine().writeLine("/*").writeLine(`|----------------------------------------------------------`).writeLine(`| ${comment}`).writeLine(`|----------------------------------------------------------`).writeLine(`*/`);
|
|
218
272
|
}
|
|
219
273
|
async defineEnvValidations(definition) {
|
|
220
|
-
const
|
|
221
|
-
const
|
|
274
|
+
const filePath = `${this.getDirectories().start}/env.ts`;
|
|
275
|
+
const envUrl = join(this.#cwdPath, `./${filePath}`);
|
|
276
|
+
const file = this.project.getSourceFile(envUrl);
|
|
277
|
+
if (!file) throw CodemodException.missingEnvFile(filePath, definition);
|
|
222
278
|
const callExpressions = file.getDescendantsOfKind(SyntaxKind.CallExpression).filter((statement) => statement.getExpression().getText() === "Env.create");
|
|
223
|
-
if (!callExpressions.length) throw
|
|
279
|
+
if (!callExpressions.length) throw CodemodException.missingEnvCreate(filePath, definition);
|
|
224
280
|
const objectLiteralExpression = callExpressions[0].getArguments()[1];
|
|
225
|
-
if (!Node.isObjectLiteralExpression(objectLiteralExpression)) throw
|
|
281
|
+
if (!Node.isObjectLiteralExpression(objectLiteralExpression)) throw CodemodException.invalidEnvCreate(filePath, definition);
|
|
226
282
|
let shouldAddComment = true;
|
|
227
283
|
for (const [variable, validation] of Object.entries(definition.variables)) {
|
|
228
284
|
const existingProperty = objectLiteralExpression.getProperty(variable);
|
|
@@ -241,10 +297,17 @@ var CodeTransformer = class {
|
|
|
241
297
|
await file.save();
|
|
242
298
|
}
|
|
243
299
|
async addMiddlewareToStack(stack, middleware) {
|
|
244
|
-
const
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
300
|
+
const filePath = `${this.getDirectories().start}/kernel.ts`;
|
|
301
|
+
const kernelUrl = join(this.#cwdPath, `./${filePath}`);
|
|
302
|
+
const file = this.project.getSourceFile(kernelUrl);
|
|
303
|
+
if (!file) throw CodemodException.missingKernelFile(filePath, stack, middleware);
|
|
304
|
+
try {
|
|
305
|
+
for (const middlewareEntry of middleware) if (stack === "named") this.#addToNamedMiddleware(file, middlewareEntry);
|
|
306
|
+
else this.#addToMiddlewareArray(file, `${stack}.use`, middlewareEntry);
|
|
307
|
+
} catch (error) {
|
|
308
|
+
if (error instanceof Error) throw CodemodException.invalidMiddlewareStack(filePath, stack, middleware, error.message);
|
|
309
|
+
throw error;
|
|
310
|
+
}
|
|
248
311
|
file.formatText(this.#editorSettings);
|
|
249
312
|
await file.save();
|
|
250
313
|
}
|
|
@@ -254,8 +317,10 @@ var CodeTransformer = class {
|
|
|
254
317
|
await rcFileTransformer.save();
|
|
255
318
|
}
|
|
256
319
|
async addJapaPlugin(pluginCall, importDeclarations) {
|
|
257
|
-
const
|
|
258
|
-
const
|
|
320
|
+
const filePath = `${this.getDirectories().tests}/bootstrap.ts`;
|
|
321
|
+
const testBootstrapUrl = join(this.#cwdPath, `./${filePath}`);
|
|
322
|
+
const file = this.project.getSourceFile(testBootstrapUrl);
|
|
323
|
+
if (!file) throw CodemodException.missingJapaBootstrap(filePath, pluginCall, importDeclarations);
|
|
259
324
|
this.#addImportDeclarations(file, importDeclarations);
|
|
260
325
|
const pluginsArray = file.getVariableDeclaration("plugins")?.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression);
|
|
261
326
|
if (pluginsArray) {
|
|
@@ -265,22 +330,36 @@ var CodeTransformer = class {
|
|
|
265
330
|
await file.save();
|
|
266
331
|
}
|
|
267
332
|
async addVitePlugin(pluginCall, importDeclarations) {
|
|
268
|
-
const
|
|
333
|
+
const filePath = "vite.config.ts";
|
|
334
|
+
const viteConfigTsUrl = join(this.#cwdPath, `./${filePath}`);
|
|
269
335
|
const file = this.project.getSourceFile(viteConfigTsUrl);
|
|
270
|
-
if (!file) throw
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
336
|
+
if (!file) throw CodemodException.missingViteConfig(filePath, pluginCall, importDeclarations);
|
|
337
|
+
try {
|
|
338
|
+
this.#addImportDeclarations(file, importDeclarations);
|
|
339
|
+
const defaultExport = file.getDefaultExportSymbol();
|
|
340
|
+
if (!defaultExport) throw new Error("Cannot find the default export in vite.config.ts");
|
|
341
|
+
const declaration = defaultExport.getDeclarations()[0];
|
|
342
|
+
const pluginsArray = (declaration.getChildrenOfKind(SyntaxKind.ObjectLiteralExpression)[0] || declaration.getChildrenOfKind(SyntaxKind.CallExpression)[0].getArguments()[0]).getPropertyOrThrow("plugins").getFirstChildByKindOrThrow(SyntaxKind.ArrayLiteralExpression);
|
|
343
|
+
if (!pluginsArray.getElements().find((element) => element.getText() === pluginCall)) pluginsArray.addElement(pluginCall);
|
|
344
|
+
} catch (error) {
|
|
345
|
+
if (error instanceof CodemodException) throw error;
|
|
346
|
+
if (error instanceof Error) throw CodemodException.invalidViteConfig(filePath, pluginCall, importDeclarations, error.message);
|
|
347
|
+
throw error;
|
|
348
|
+
}
|
|
277
349
|
file.formatText(this.#editorSettings);
|
|
278
350
|
await file.save();
|
|
279
351
|
}
|
|
280
352
|
async addPolicies(policies) {
|
|
281
|
-
const
|
|
282
|
-
const
|
|
283
|
-
|
|
353
|
+
const filePath = `${this.getDirectories().policies}/main.ts`;
|
|
354
|
+
const policiesUrl = join(this.#cwdPath, `./${filePath}`);
|
|
355
|
+
const file = this.project.getSourceFile(policiesUrl);
|
|
356
|
+
if (!file) throw CodemodException.missingPoliciesFile(filePath, policies);
|
|
357
|
+
try {
|
|
358
|
+
for (const policy of policies) this.#addToPoliciesList(file, policy);
|
|
359
|
+
} catch (error) {
|
|
360
|
+
if (error instanceof Error) throw CodemodException.invalidPoliciesFile(filePath, policies, error.message);
|
|
361
|
+
throw error;
|
|
362
|
+
}
|
|
284
363
|
file.formatText(this.#editorSettings);
|
|
285
364
|
await file.save();
|
|
286
365
|
}
|
|
@@ -82,12 +82,38 @@ export declare class RcFileTransformer {
|
|
|
82
82
|
addSuite(suiteName: string, files: string | string[], timeout?: number): this;
|
|
83
83
|
/**
|
|
84
84
|
* Add a new assembler hook
|
|
85
|
+
* The format `thunk` write `() => import(path)`.
|
|
85
86
|
*
|
|
86
87
|
* @param type - The type of hook to add
|
|
87
|
-
* @param
|
|
88
|
+
* @param value - The path to the hook file or value to write
|
|
89
|
+
* @param raw - Wether to write a thunk import or as raw value
|
|
88
90
|
* @returns This RcFileTransformer instance for method chaining
|
|
89
91
|
*/
|
|
90
|
-
addAssemblerHook(type: keyof Exclude<AssemblerRcFile['hooks'], undefined>,
|
|
92
|
+
addAssemblerHook(type: keyof Exclude<AssemblerRcFile['hooks'], undefined>, value: string, raw?: boolean): this;
|
|
93
|
+
/**
|
|
94
|
+
* Add a named import
|
|
95
|
+
*
|
|
96
|
+
* @param specifier - The module specifier to import
|
|
97
|
+
* @param names - Names to import from the module
|
|
98
|
+
* @returns This RcFileTransformer instance for method chaining
|
|
99
|
+
*/
|
|
100
|
+
addNamedImport(specifier: string, names: string[]): this;
|
|
101
|
+
/**
|
|
102
|
+
* Add a default import
|
|
103
|
+
*
|
|
104
|
+
* @param specifier - The module specifier to import
|
|
105
|
+
* @param name - Name of the default import
|
|
106
|
+
* @returns This RcFileTransformer instance for method chaining
|
|
107
|
+
*/
|
|
108
|
+
addDefaultImport(specifier: string, name: string): this;
|
|
109
|
+
/**
|
|
110
|
+
* Get a directory value from the directories configuration.
|
|
111
|
+
*
|
|
112
|
+
* @param key - The directory key to retrieve
|
|
113
|
+
* @param defaultValue - The default value if not configured
|
|
114
|
+
* @returns The configured directory path or the default value
|
|
115
|
+
*/
|
|
116
|
+
getDirectory(key: string, defaultValue: string): string;
|
|
91
117
|
/**
|
|
92
118
|
* Save the adonisrc.ts file with all applied transformations
|
|
93
119
|
*
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import type { MiddlewareNode, EnvValidationNode, BouncerPolicyNode } from '../types/code_transformer.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Options for creating a CodemodException
|
|
4
|
+
*/
|
|
5
|
+
export interface CodemodExceptionOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Instructions for the user to manually perform the codemod action
|
|
8
|
+
*/
|
|
9
|
+
instructions?: string;
|
|
10
|
+
/**
|
|
11
|
+
* The file path that was being modified
|
|
12
|
+
*/
|
|
13
|
+
filePath?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Custom exception for codemod errors that provides helpful instructions
|
|
17
|
+
* to the user when automatic code transformation fails.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* throw CodemodException.missingEnvFile('start/env.ts', {
|
|
22
|
+
* variables: { MY_VAR: 'Env.schema.string()' }
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class CodemodException extends Error {
|
|
27
|
+
#private;
|
|
28
|
+
/**
|
|
29
|
+
* Instructions for the user to manually perform the codemod action
|
|
30
|
+
*/
|
|
31
|
+
instructions?: string;
|
|
32
|
+
/**
|
|
33
|
+
* The file path that was being modified
|
|
34
|
+
*/
|
|
35
|
+
filePath?: string;
|
|
36
|
+
constructor(message: string, options?: CodemodExceptionOptions);
|
|
37
|
+
/**
|
|
38
|
+
* Creates an exception when start/env.ts file is missing
|
|
39
|
+
*
|
|
40
|
+
* @param filePath - The path to the missing file
|
|
41
|
+
* @param definition - The environment validation definition that was being added
|
|
42
|
+
*/
|
|
43
|
+
static missingEnvFile(filePath: string, definition: EnvValidationNode): CodemodException;
|
|
44
|
+
/**
|
|
45
|
+
* Creates an exception when Env.create is not found in the file
|
|
46
|
+
*
|
|
47
|
+
* @param filePath - The path to the file being modified
|
|
48
|
+
* @param definition - The environment validation definition that was being added
|
|
49
|
+
*/
|
|
50
|
+
static missingEnvCreate(filePath: string, definition: EnvValidationNode): CodemodException;
|
|
51
|
+
/**
|
|
52
|
+
* Creates an exception when Env.create has invalid structure
|
|
53
|
+
*
|
|
54
|
+
* @param filePath - The path to the file being modified
|
|
55
|
+
* @param definition - The environment validation definition that was being added
|
|
56
|
+
*/
|
|
57
|
+
static invalidEnvCreate(filePath: string, definition: EnvValidationNode): CodemodException;
|
|
58
|
+
/**
|
|
59
|
+
* Creates an exception when start/kernel.ts file is missing
|
|
60
|
+
*
|
|
61
|
+
* @param filePath - The path to the missing file
|
|
62
|
+
* @param stack - The middleware stack that was being modified
|
|
63
|
+
* @param middleware - The middleware entries that were being added
|
|
64
|
+
*/
|
|
65
|
+
static missingKernelFile(filePath: string, stack: 'server' | 'router' | 'named', middleware: MiddlewareNode[]): CodemodException;
|
|
66
|
+
/**
|
|
67
|
+
* Creates an exception when server.use/router.use is not found
|
|
68
|
+
*
|
|
69
|
+
* @param filePath - The path to the file being modified
|
|
70
|
+
* @param stack - The middleware stack that was being modified
|
|
71
|
+
* @param middleware - The middleware entries that were being added
|
|
72
|
+
*/
|
|
73
|
+
static missingMiddlewareStack(filePath: string, stack: 'server' | 'router' | 'named', middleware: MiddlewareNode[]): CodemodException;
|
|
74
|
+
/**
|
|
75
|
+
* Creates an exception when middleware array structure is invalid
|
|
76
|
+
*
|
|
77
|
+
* @param filePath - The path to the file being modified
|
|
78
|
+
* @param stack - The middleware stack that was being modified
|
|
79
|
+
* @param middleware - The middleware entries that were being added
|
|
80
|
+
* @param reason - The reason why the structure is invalid
|
|
81
|
+
*/
|
|
82
|
+
static invalidMiddlewareStack(filePath: string, stack: 'server' | 'router' | 'named', middleware: MiddlewareNode[], reason: string): CodemodException;
|
|
83
|
+
/**
|
|
84
|
+
* Creates an exception when app/policies/main.ts file is missing
|
|
85
|
+
*
|
|
86
|
+
* @param filePath - The path to the missing file
|
|
87
|
+
* @param policies - The policies that were being added
|
|
88
|
+
*/
|
|
89
|
+
static missingPoliciesFile(filePath: string, policies: BouncerPolicyNode[]): CodemodException;
|
|
90
|
+
/**
|
|
91
|
+
* Creates an exception when policies structure is invalid
|
|
92
|
+
*
|
|
93
|
+
* @param filePath - The path to the file being modified
|
|
94
|
+
* @param policies - The policies that were being added
|
|
95
|
+
* @param reason - The reason why the structure is invalid
|
|
96
|
+
*/
|
|
97
|
+
static invalidPoliciesFile(filePath: string, policies: BouncerPolicyNode[], reason: string): CodemodException;
|
|
98
|
+
/**
|
|
99
|
+
* Creates an exception when vite.config.ts file is missing
|
|
100
|
+
*
|
|
101
|
+
* @param filePath - The path to the missing file
|
|
102
|
+
* @param pluginCall - The plugin call that was being added
|
|
103
|
+
* @param importDeclarations - The import declarations needed for the plugin
|
|
104
|
+
*/
|
|
105
|
+
static missingViteConfig(filePath: string, pluginCall: string, importDeclarations: {
|
|
106
|
+
isNamed: boolean;
|
|
107
|
+
module: string;
|
|
108
|
+
identifier: string;
|
|
109
|
+
}[]): CodemodException;
|
|
110
|
+
/**
|
|
111
|
+
* Creates an exception when vite.config.ts structure is invalid
|
|
112
|
+
*
|
|
113
|
+
* @param filePath - The path to the file being modified
|
|
114
|
+
* @param pluginCall - The plugin call that was being added
|
|
115
|
+
* @param importDeclarations - The import declarations needed for the plugin
|
|
116
|
+
* @param reason - The reason why the structure is invalid
|
|
117
|
+
*/
|
|
118
|
+
static invalidViteConfig(filePath: string, pluginCall: string, importDeclarations: {
|
|
119
|
+
isNamed: boolean;
|
|
120
|
+
module: string;
|
|
121
|
+
identifier: string;
|
|
122
|
+
}[], reason: string): CodemodException;
|
|
123
|
+
/**
|
|
124
|
+
* Creates an exception when tests/bootstrap.ts file is missing
|
|
125
|
+
*
|
|
126
|
+
* @param filePath - The path to the missing file
|
|
127
|
+
* @param pluginCall - The plugin call that was being added
|
|
128
|
+
* @param importDeclarations - The import declarations needed for the plugin
|
|
129
|
+
*/
|
|
130
|
+
static missingJapaBootstrap(filePath: string, pluginCall: string, importDeclarations: {
|
|
131
|
+
isNamed: boolean;
|
|
132
|
+
module: string;
|
|
133
|
+
identifier: string;
|
|
134
|
+
}[]): CodemodException;
|
|
135
|
+
/**
|
|
136
|
+
* Creates an exception when tests/bootstrap.ts structure is invalid
|
|
137
|
+
*
|
|
138
|
+
* @param filePath - The path to the file being modified
|
|
139
|
+
* @param pluginCall - The plugin call that was being added
|
|
140
|
+
* @param importDeclarations - The import declarations needed for the plugin
|
|
141
|
+
* @param reason - The reason why the structure is invalid
|
|
142
|
+
*/
|
|
143
|
+
static invalidJapaBootstrap(filePath: string, pluginCall: string, importDeclarations: {
|
|
144
|
+
isNamed: boolean;
|
|
145
|
+
module: string;
|
|
146
|
+
identifier: string;
|
|
147
|
+
}[], reason: string): CodemodException;
|
|
148
|
+
/**
|
|
149
|
+
* Creates an exception when adonisrc.ts file is missing
|
|
150
|
+
*
|
|
151
|
+
* @param filePath - The path to the missing file
|
|
152
|
+
* @param codeToAdd - The code that should be added manually
|
|
153
|
+
*/
|
|
154
|
+
static missingRcFile(filePath: string, codeToAdd: string): CodemodException;
|
|
155
|
+
/**
|
|
156
|
+
* Creates an exception when adonisrc.ts structure is invalid
|
|
157
|
+
*
|
|
158
|
+
* @param filePath - The path to the file being modified
|
|
159
|
+
* @param codeToAdd - The code that should be added manually
|
|
160
|
+
* @param reason - The reason why the structure is invalid
|
|
161
|
+
*/
|
|
162
|
+
static invalidRcFile(filePath: string, codeToAdd: string, reason: string): CodemodException;
|
|
163
|
+
/**
|
|
164
|
+
* Creates an exception when a file required for transformation is not found.
|
|
165
|
+
*
|
|
166
|
+
* @param filePath - The path to the missing file
|
|
167
|
+
* @param codeToAdd - The code that should be added manually
|
|
168
|
+
*/
|
|
169
|
+
static E_CODEMOD_FILE_NOT_FOUND(filePath: string, codeToAdd: string): CodemodException;
|
|
170
|
+
/**
|
|
171
|
+
* Creates an exception when the file structure doesn't match expected patterns.
|
|
172
|
+
*
|
|
173
|
+
* @param message - Description of what structure was expected
|
|
174
|
+
* @param filePath - The path to the file being modified
|
|
175
|
+
* @param codeToAdd - The code that should be added manually
|
|
176
|
+
*/
|
|
177
|
+
static E_CODEMOD_INVALID_STRUCTURE(message: string, filePath: string, codeToAdd: string): CodemodException;
|
|
178
|
+
}
|
|
@@ -90,6 +90,14 @@ export type EnvValidationNode = {
|
|
|
90
90
|
*/
|
|
91
91
|
variables: Record<string, string>;
|
|
92
92
|
};
|
|
93
|
+
export type HookNode = {
|
|
94
|
+
type: 'thunk';
|
|
95
|
+
path: string;
|
|
96
|
+
} | {
|
|
97
|
+
type: 'import';
|
|
98
|
+
path: string;
|
|
99
|
+
name?: string;
|
|
100
|
+
};
|
|
93
101
|
/**
|
|
94
102
|
* The supported package managers for installing packages and managing lockfiles.
|
|
95
103
|
* Each package manager has specific lockfiles and install commands.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonisjs/assembler",
|
|
3
3
|
"description": "Provides utilities to run AdonisJS development server and build project for production",
|
|
4
|
-
"version": "8.0.0-next.
|
|
4
|
+
"version": "8.0.0-next.29",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=24.0.0"
|
|
7
7
|
},
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"quick:test": "cross-env NODE_DEBUG=adonisjs:assembler node --enable-source-maps --import=@poppinss/ts-exec bin/test.ts"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@adonisjs/eslint-config": "^3.0.0-next.
|
|
40
|
+
"@adonisjs/eslint-config": "^3.0.0-next.9",
|
|
41
41
|
"@adonisjs/prettier-config": "^1.4.5",
|
|
42
42
|
"@adonisjs/tsconfig": "^2.0.0-next.3",
|
|
43
43
|
"@japa/assert": "^4.2.0",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"@japa/runner": "^5.0.0",
|
|
46
46
|
"@japa/snapshot": "^2.0.10",
|
|
47
47
|
"@poppinss/ts-exec": "^1.4.1",
|
|
48
|
-
"@release-it/conventional-changelog": "^10.0.
|
|
49
|
-
"@types/node": "^25.0.
|
|
48
|
+
"@release-it/conventional-changelog": "^10.0.4",
|
|
49
|
+
"@types/node": "^25.0.3",
|
|
50
50
|
"@types/picomatch": "^4.0.2",
|
|
51
51
|
"@types/pretty-hrtime": "^1.0.3",
|
|
52
52
|
"c8": "^10.1.3",
|
|
@@ -54,22 +54,22 @@
|
|
|
54
54
|
"del-cli": "^7.0.0",
|
|
55
55
|
"eslint": "^9.39.2",
|
|
56
56
|
"hot-hook": "^0.4.1-next.2",
|
|
57
|
-
"p-event": "^7.0.
|
|
57
|
+
"p-event": "^7.0.2",
|
|
58
58
|
"prettier": "^3.7.4",
|
|
59
|
-
"release-it": "^19.
|
|
60
|
-
"tsdown": "^0.
|
|
59
|
+
"release-it": "^19.2.2",
|
|
60
|
+
"tsdown": "^0.18.4",
|
|
61
61
|
"typedoc": "^0.28.15",
|
|
62
62
|
"typescript": "^5.9.3"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@adonisjs/env": "^7.0.0-next.
|
|
65
|
+
"@adonisjs/env": "^7.0.0-next.3",
|
|
66
66
|
"@antfu/install-pkg": "^1.1.0",
|
|
67
|
-
"@ast-grep/napi": "^0.40.
|
|
67
|
+
"@ast-grep/napi": "^0.40.3",
|
|
68
68
|
"@poppinss/cliui": "^6.6.0",
|
|
69
69
|
"@poppinss/hooks": "^7.3.0",
|
|
70
|
-
"@poppinss/utils": "^7.0.0-next.
|
|
70
|
+
"@poppinss/utils": "^7.0.0-next.5",
|
|
71
71
|
"chokidar": "^5.0.0",
|
|
72
|
-
"dedent": "^1.7.
|
|
72
|
+
"dedent": "^1.7.1",
|
|
73
73
|
"execa": "^9.6.1",
|
|
74
74
|
"fast-glob": "^3.3.3",
|
|
75
75
|
"fdir": "^6.5.0",
|