@adonisjs/assembler 8.0.0-next.9 → 8.0.1

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 (35) hide show
  1. package/README.md +260 -0
  2. package/build/chunk-DF48asd8.js +9 -0
  3. package/build/codemod_exception-BMNJZ0i1.js +280 -0
  4. package/build/index.d.ts +1 -1
  5. package/build/index.js +1854 -1724
  6. package/build/main-Cpfvmdw6.js +562 -0
  7. package/build/main-INOi9swJ.js +471 -0
  8. package/build/src/bundler.d.ts +2 -0
  9. package/build/src/code_scanners/routes_scanner/main.d.ts +16 -2
  10. package/build/src/code_scanners/routes_scanner/main.js +4 -445
  11. package/build/src/code_transformer/main.d.ts +14 -1
  12. package/build/src/code_transformer/main.js +981 -622
  13. package/build/src/code_transformer/rc_file_transformer.d.ts +28 -2
  14. package/build/src/debug.d.ts +1 -1
  15. package/build/src/dev_server.d.ts +60 -12
  16. package/build/src/exceptions/codemod_exception.d.ts +178 -0
  17. package/build/src/file_buffer.d.ts +19 -0
  18. package/build/src/file_system.d.ts +3 -3
  19. package/build/src/helpers.js +205 -16
  20. package/build/src/index_generator/main.js +4 -7
  21. package/build/src/paths_resolver.d.ts +2 -1
  22. package/build/src/test_runner.d.ts +3 -2
  23. package/build/src/types/code_scanners.d.ts +29 -13
  24. package/build/src/types/code_transformer.d.ts +127 -0
  25. package/build/src/types/common.d.ts +98 -2
  26. package/build/src/types/hooks.d.ts +4 -1
  27. package/build/src/types/main.js +2 -0
  28. package/build/src/utils.d.ts +7 -3
  29. package/build/src/virtual_file_system.d.ts +1 -1
  30. package/build/virtual_file_system-dzfXNwEp.js +572 -0
  31. package/package.json +41 -39
  32. package/build/chunk-7XU453QB.js +0 -418
  33. package/build/chunk-PORDZS62.js +0 -391
  34. package/build/chunk-TIKQQRMX.js +0 -116
  35. package/build/src/hooks.d.ts +0 -224
@@ -0,0 +1,471 @@
1
+ import { f as throttle, l as removeExtension, m as debug_default, t as VirtualFileSystem } from "./virtual_file_system-dzfXNwEp.js";
2
+ import { mkdir, writeFile } from "node:fs/promises";
3
+ import string from "@poppinss/utils/string";
4
+ import { dirname, join, relative } from "node:path/posix";
5
+ import StringBuilder from "@poppinss/utils/string_builder";
6
+ //#region src/file_buffer.ts
7
+ /**
8
+ * Buffer class to construct template output with proper indentation and formatting.
9
+ *
10
+ * The FileBuffer class provides a fluent API for building text output with automatic
11
+ * indentation management. It's commonly used for generating code or template files
12
+ * where proper formatting is important.
13
+ *
14
+ * @example
15
+ * const buffer = new FileBuffer()
16
+ * buffer
17
+ * .writeLine('function example() {')
18
+ * .indent()
19
+ * .writeLine('return "Hello World"')
20
+ * .dedent()
21
+ * .writeLine('}')
22
+ * console.log(buffer.flush())
23
+ */
24
+ var FileBuffer = class FileBuffer {
25
+ /**
26
+ * Whether to add an end-of-line character at the end of the output
27
+ */
28
+ #eol = false;
29
+ /**
30
+ * Collected lines
31
+ */
32
+ #buffer = [];
33
+ /**
34
+ * Current indentation size. Each call to indent will increment
35
+ * it by 2
36
+ */
37
+ #identationSize = 0;
38
+ /**
39
+ * Cached compiled output. Once this value is set, the `flush`
40
+ * method will become a noop
41
+ */
42
+ #compiledOutput;
43
+ /**
44
+ * Creates a new child buffer instance
45
+ *
46
+ * @returns A new FileBuffer instance
47
+ */
48
+ create() {
49
+ return new FileBuffer();
50
+ }
51
+ /**
52
+ * Returns the size of buffer text
53
+ *
54
+ * @returns The number of lines in the buffer
55
+ */
56
+ get size() {
57
+ return this.#buffer.length;
58
+ }
59
+ /**
60
+ * Enable or disable end-of-line character at the end of output
61
+ *
62
+ * @param enabled - Whether to add EOL character
63
+ * @returns This FileBuffer instance for method chaining
64
+ *
65
+ * @example
66
+ * const buffer = new FileBuffer()
67
+ * buffer.eol(true).writeLine('Hello').flush() // 'Hello\n\n'
68
+ */
69
+ eol(enabled) {
70
+ this.#eol = enabled;
71
+ return this;
72
+ }
73
+ /**
74
+ * Write a new line to the output with current indentation
75
+ *
76
+ * @param text - The text to write as a new line
77
+ * @returns This FileBuffer instance for method chaining
78
+ */
79
+ writeLine(text) {
80
+ if (typeof text === "string") this.#buffer.push(`${" ".repeat(this.#identationSize)}${text}\n`);
81
+ else {
82
+ this.#buffer.push(text);
83
+ this.#buffer.push("");
84
+ }
85
+ return this;
86
+ }
87
+ /**
88
+ * Write text to the output without adding a new line
89
+ *
90
+ * @param text - The text to write without a newline
91
+ * @returns This FileBuffer instance for method chaining
92
+ */
93
+ write(text) {
94
+ if (typeof text === "string") this.#buffer.push(`${" ".repeat(this.#identationSize)}${text}`);
95
+ else this.#buffer.push(text);
96
+ return this;
97
+ }
98
+ /**
99
+ * Increase indentation by 2 spaces
100
+ *
101
+ * @returns This FileBuffer instance for method chaining
102
+ */
103
+ indent() {
104
+ this.#identationSize += 2;
105
+ return this;
106
+ }
107
+ /**
108
+ * Decrease indentation by 2 spaces (minimum of 0)
109
+ *
110
+ * @returns This FileBuffer instance for method chaining
111
+ */
112
+ dedent() {
113
+ this.#identationSize -= 2;
114
+ if (this.#identationSize < 0) this.#identationSize = 0;
115
+ return this;
116
+ }
117
+ /**
118
+ * Convert the buffer to a string representation
119
+ *
120
+ * @example
121
+ * const buffer = new FileBuffer()
122
+ * buffer.writeLine('Hello')
123
+ * console.log(buffer.toString())
124
+ */
125
+ toString() {
126
+ return this.flush();
127
+ }
128
+ /**
129
+ * Return template as a string, joining all buffer lines
130
+ *
131
+ * Once called, the output is cached and subsequent calls return the same result.
132
+ * The flush method becomes a no-op after the first call.
133
+ *
134
+ * @returns The complete buffer content as a string
135
+ */
136
+ flush() {
137
+ if (this.#compiledOutput !== void 0) return this.#compiledOutput;
138
+ this.#compiledOutput = this.#buffer.join("\n");
139
+ return this.#eol ? `${this.#compiledOutput}\n` : this.#compiledOutput;
140
+ }
141
+ };
142
+ //#endregion
143
+ //#region src/index_generator/source.ts
144
+ /**
145
+ * IndexGeneratorSource handles the generation of a single index file.
146
+ *
147
+ * This class is responsible for scanning a source directory, processing files
148
+ * according to configuration, and generating an index file that exports the
149
+ * discovered modules. It supports both barrel file generation and custom
150
+ * generation strategies.
151
+ *
152
+ * @example
153
+ * const source = new IndexGeneratorSource(appRoot, {
154
+ * source: 'app/controllers',
155
+ * output: 'app/controllers/index.ts',
156
+ * as: 'barrelFile',
157
+ * exportName: 'controllers'
158
+ * })
159
+ * await source.generate()
160
+ */
161
+ var IndexGeneratorSource = class {
162
+ /**
163
+ * The application root directory path
164
+ */
165
+ #appRoot;
166
+ /**
167
+ * The absolute path to the output file
168
+ */
169
+ #output;
170
+ /**
171
+ * The absolute path to the source directory
172
+ */
173
+ #source;
174
+ /**
175
+ * The directory containing the output file
176
+ */
177
+ #outputDirname;
178
+ /**
179
+ * Virtual file system for scanning source files
180
+ */
181
+ #vfs;
182
+ /**
183
+ * Configuration for this index generator source
184
+ */
185
+ #config;
186
+ /**
187
+ * CLI logger instance for output messages
188
+ */
189
+ #cliLogger;
190
+ /**
191
+ * Generate the output content and write it to the output file
192
+ *
193
+ * This method creates the file buffer, populates it with the generated
194
+ * content based on configuration, and writes it to disk.
195
+ */
196
+ #generateOutput = throttle(async () => {
197
+ const buffer = new FileBuffer().eol(true);
198
+ if (this.#config.comment) buffer.writeLine(this.#textToComment(typeof this.#config.comment === "string" ? this.#config.comment : `This file is automatically generated.\nDO NOT EDIT manually`));
199
+ if (this.#config.as === "barrelFile") this.#asBarrelFile(this.#vfs, buffer, this.#config.exportName, this.#config.disableLazyImports);
200
+ else this.#config.as(this.#vfs, buffer, this.#config, { toImportPath: this.#createBarrelFileImportGenerator(this.#source, this.#outputDirname, this.#config) });
201
+ await mkdir(dirname(this.#output), { recursive: true });
202
+ await writeFile(this.#output, buffer.flush());
203
+ });
204
+ /**
205
+ * Unique name for this index generator source
206
+ */
207
+ name;
208
+ /**
209
+ * Create a new IndexGeneratorSource instance
210
+ *
211
+ * @param name - Unique name for this index generator source
212
+ * @param appRoot - The application root directory path
213
+ * @param cliLogger - Logger instance for CLI output
214
+ * @param config - Configuration for this index generator source
215
+ */
216
+ constructor(name, appRoot, cliLogger, config) {
217
+ this.name = name;
218
+ this.#config = config;
219
+ this.#appRoot = appRoot;
220
+ this.#cliLogger = cliLogger;
221
+ this.#source = join(this.#appRoot, this.#config.source);
222
+ this.#output = join(this.#appRoot, this.#config.output);
223
+ this.#outputDirname = dirname(this.#output);
224
+ this.#vfs = new VirtualFileSystem(this.#source, {
225
+ glob: this.#config.glob,
226
+ filter: this.#config.filter
227
+ });
228
+ }
229
+ /**
230
+ * Converts a recursive file tree to a string representation
231
+ *
232
+ * This method recursively processes a file tree structure and writes
233
+ * it as JavaScript object notation to the provided buffer.
234
+ *
235
+ * @param input - The recursive file tree to convert
236
+ * @param buffer - The file buffer to write the output to
237
+ */
238
+ #treeToString(input, buffer) {
239
+ Object.keys(input).forEach((key) => {
240
+ const value = input[key];
241
+ if (typeof value === "string") buffer.write(`${key}: ${value},`);
242
+ else {
243
+ buffer.write(`${key}: {`).indent();
244
+ this.#treeToString(value, buffer);
245
+ buffer.dedent().write(`},`);
246
+ }
247
+ });
248
+ }
249
+ /**
250
+ * Converts a text into a JS comment block. Respecting line-breaks.
251
+ */
252
+ #textToComment(text) {
253
+ return `/**\n * ${text.split("\n").join("\n * ")}\n */`;
254
+ }
255
+ /**
256
+ * Transforms the barrel file index key. Converts basename to PascalCase
257
+ * and all other paths to camelCase
258
+ *
259
+ * @param config - Configuration containing suffix removal options
260
+ * @returns Function that transforms file paths to appropriate keys
261
+ */
262
+ #createBarrelFileKeyGenerator(config) {
263
+ return function(key) {
264
+ let paths = key.split("/");
265
+ let baseName = new StringBuilder(paths.pop());
266
+ if (config.skipSegments?.length) paths = paths.filter((p) => !config.skipSegments.includes(p));
267
+ if (config.computeBaseName) baseName = config.computeBaseName(baseName);
268
+ else baseName = baseName.removeSuffix(config.removeSuffix ?? "").pascalCase();
269
+ return [...paths.map((p) => string.camelCase(p)), baseName.toString()].join("/");
270
+ };
271
+ }
272
+ /**
273
+ * Converts the file path to a lazy import. In case of an alias, the source
274
+ * path is replaced with the alias, otherwise a relative import is created
275
+ * from the output dirname.
276
+ *
277
+ * @param source - The source directory path
278
+ * @param outputDirname - The output directory path
279
+ * @param config - Configuration containing import alias options
280
+ * @returns Function that converts file paths to import statements
281
+ */
282
+ #createBarrelFileImportGenerator(source, outputDirname, config) {
283
+ return function(filePath) {
284
+ if (config.importAlias) {
285
+ debug_default("converting \"%s\" to import alias, source \"%s\"", filePath, source);
286
+ return removeExtension(filePath.replace(source, config.importAlias));
287
+ }
288
+ debug_default("converting \"%s\" to relative import, source \"%s\"", filePath, outputDirname);
289
+ return relative(outputDirname, filePath);
290
+ };
291
+ }
292
+ /**
293
+ * Generate a barrel file export structure
294
+ *
295
+ * This method creates a nested object structure that represents all
296
+ * discovered files as lazy imports, organized by directory structure.
297
+ *
298
+ * @param vfs - Virtual file system containing the scanned files
299
+ * @param buffer - File buffer to write the barrel exports to
300
+ * @param exportName - Name for the main export object
301
+ */
302
+ #asBarrelFile(vfs, buffer, exportName, disableLazyImports) {
303
+ const useEagerImports = disableLazyImports === true ? true : false;
304
+ const keyGenerator = this.#createBarrelFileKeyGenerator(this.#config);
305
+ const importsBuffer = buffer.create();
306
+ const importGenerator = this.#createBarrelFileImportGenerator(this.#source, this.#outputDirname, this.#config);
307
+ const tree = vfs.asTree({
308
+ transformKey: keyGenerator,
309
+ transformValue: (filePath, key) => {
310
+ if (useEagerImports) {
311
+ const importKey = new StringBuilder(key).pascalCase().toString();
312
+ importsBuffer.write(`import ${importKey} from '${importGenerator(filePath)}'`);
313
+ return importKey;
314
+ }
315
+ return `() => import('${importGenerator(filePath)}')`;
316
+ }
317
+ });
318
+ if (!Object.keys(tree).length) {
319
+ buffer.write(`export const ${exportName} = {}`);
320
+ return;
321
+ }
322
+ if (useEagerImports) buffer.writeLine(importsBuffer);
323
+ buffer.write(`export const ${exportName} = {`).indent();
324
+ this.#treeToString(tree, buffer);
325
+ buffer.dedent().write(`}`);
326
+ }
327
+ /**
328
+ * Displays the log message after generating the index file
329
+ *
330
+ * @example
331
+ * const startTime = process.hrtime()
332
+ * // ... perform operations
333
+ * this.#logCreation(startTime)
334
+ */
335
+ #logCreation(startTime) {
336
+ this.#cliLogger.info(`created ${this.#config.output}`, { startTime });
337
+ }
338
+ /**
339
+ * Add a file to the virtual file system and regenerate index if needed
340
+ *
341
+ * If the file matches the configured glob patterns, it will be added
342
+ * to the virtual file system and the index file will be regenerated.
343
+ *
344
+ * @param filePath - Absolute path of the file to add
345
+ */
346
+ async addFile(filePath) {
347
+ if (this.#vfs.add(filePath)) {
348
+ debug_default("file added, re-generating \"%s\" index", this.name);
349
+ const startTime = process.hrtime();
350
+ await this.#generateOutput();
351
+ this.#logCreation(startTime);
352
+ }
353
+ }
354
+ /**
355
+ * Remove a file from the virtual file system and regenerate index if needed
356
+ *
357
+ * If the file was previously tracked, it will be removed from the
358
+ * virtual file system and the index file will be regenerated.
359
+ *
360
+ * @param filePath - Absolute path of the file to remove
361
+ */
362
+ async removeFile(filePath) {
363
+ if (this.#vfs.remove(filePath)) {
364
+ debug_default("file removed, re-generating \"%s\" index", this.name);
365
+ const startTime = process.hrtime();
366
+ await this.#generateOutput();
367
+ this.#logCreation(startTime);
368
+ }
369
+ }
370
+ /**
371
+ * Generate the index file
372
+ *
373
+ * This method scans the source directory, processes files according to
374
+ * the configuration, and writes the generated index file to disk.
375
+ */
376
+ async generate() {
377
+ debug_default("generating \"%s\" index", this.name);
378
+ await this.#vfs.scan();
379
+ await this.#generateOutput();
380
+ }
381
+ };
382
+ //#endregion
383
+ //#region src/index_generator/main.ts
384
+ /**
385
+ * IndexGenerator manages the generation of index files for AdonisJS applications.
386
+ *
387
+ * This class provides a way to configure multiple sources and generate index files
388
+ * that export collections of modules, typically used for barrel exports or
389
+ * auto-discovery patterns in AdonisJS applications.
390
+ *
391
+ * @example
392
+ * const generator = new IndexGenerator(appRoot)
393
+ * generator.add('controllers', {
394
+ * source: 'app/controllers',
395
+ * output: 'app/controllers/index.ts',
396
+ * as: 'barrelFile',
397
+ * exportName: 'controllers'
398
+ * })
399
+ * await generator.generate()
400
+ */
401
+ var IndexGenerator = class {
402
+ /**
403
+ * The application root directory path
404
+ */
405
+ appRoot;
406
+ /**
407
+ * Collection of registered index generator sources
408
+ */
409
+ #sources = {};
410
+ #cliLogger;
411
+ /**
412
+ * Create a new IndexGenerator instance
413
+ *
414
+ * @param appRoot - The application root directory path
415
+ * @param cliLogger - Logger instance for CLI output
416
+ */
417
+ constructor(appRoot, cliLogger) {
418
+ this.appRoot = appRoot;
419
+ this.#cliLogger = cliLogger;
420
+ }
421
+ /**
422
+ * Add a new index generator source
423
+ *
424
+ * @param name - Unique name for the source
425
+ * @param config - Configuration for the index generator source
426
+ * @returns This IndexGenerator instance for method chaining
427
+ */
428
+ add(name, config) {
429
+ this.#sources[name] = new IndexGeneratorSource(name, this.appRoot, this.#cliLogger, config);
430
+ return this;
431
+ }
432
+ /**
433
+ * Add a file to all registered index generator sources
434
+ *
435
+ * This method propagates the file addition to all registered sources,
436
+ * allowing them to regenerate their index files if the new file matches
437
+ * their glob patterns.
438
+ *
439
+ * @param filePath - Absolute path of the file to add
440
+ */
441
+ async addFile(filePath) {
442
+ const sources = Object.values(this.#sources);
443
+ for (let source of sources) await source.addFile(filePath);
444
+ }
445
+ /**
446
+ * Remove a file from all registered index generator sources
447
+ *
448
+ * This method propagates the file removal to all registered sources,
449
+ * allowing them to regenerate their index files if the removed file
450
+ * was previously tracked.
451
+ *
452
+ * @param filePath - Absolute path of the file to remove
453
+ */
454
+ async removeFile(filePath) {
455
+ const sources = Object.values(this.#sources);
456
+ for (let source of sources) await source.removeFile(filePath);
457
+ }
458
+ /**
459
+ * Generate all registered index files
460
+ *
461
+ * Iterates through all registered sources and generates their
462
+ * corresponding index files.
463
+ */
464
+ async generate() {
465
+ const sources = Object.values(this.#sources);
466
+ for (let source of sources) await source.generate();
467
+ if (sources.length) this.#cliLogger.info(`codegen: created ${sources.length} file(s)`);
468
+ }
469
+ };
470
+ //#endregion
471
+ export { FileBuffer as n, IndexGenerator as t };
@@ -28,6 +28,7 @@ export declare class Bundler {
28
28
  logger: import("@poppinss/cliui").Logger;
29
29
  table: (tableOptions?: Partial<import("@poppinss/cliui/types").TableOptions>) => import("@poppinss/cliui").Table;
30
30
  tasks: (tasksOptions?: Partial<import("@poppinss/cliui/types").TaskManagerOptions>) => import("@poppinss/cliui").TaskManager;
31
+ steps: () => import("@poppinss/cliui").Steps;
31
32
  icons: {
32
33
  tick: string;
33
34
  cross: string;
@@ -37,6 +38,7 @@ export declare class Bundler {
37
38
  info: string;
38
39
  warning: string;
39
40
  squareSmallFilled: string;
41
+ borderVertical: string;
40
42
  };
41
43
  sticker: () => import("@poppinss/cliui").Instructions;
42
44
  instructions: () => import("@poppinss/cliui").Instructions;
@@ -1,6 +1,6 @@
1
1
  import { type AsyncOrSync } from '@poppinss/utils/types';
2
2
  import { PathsResolver } from '../../paths_resolver.ts';
3
- import { type ScannedRoute, type RoutesListItem, type ScannedController, type RoutesScannerRules } from '../../types/code_scanners.ts';
3
+ import { type ScannedRoute, type RoutesListItem, type ScannedController, type RoutesScannerRules, type RoutesScannerFilterFn } from '../../types/code_scanners.ts';
4
4
  /**
5
5
  * RoutesScanner is responsible for scanning application routes,
6
6
  * extracting their controllers, validators, request and response types.
@@ -27,6 +27,7 @@ export declare class RoutesScanner {
27
27
  logger: import("@poppinss/cliui").Logger;
28
28
  table: (tableOptions?: Partial<import("@poppinss/cliui/types").TableOptions>) => import("@poppinss/cliui").Table;
29
29
  tasks: (tasksOptions?: Partial<import("@poppinss/cliui/types").TaskManagerOptions>) => import("@poppinss/cliui").TaskManager;
30
+ steps: () => import("@poppinss/cliui").Steps;
30
31
  icons: {
31
32
  tick: string;
32
33
  cross: string;
@@ -36,6 +37,7 @@ export declare class RoutesScanner {
36
37
  info: string;
37
38
  warning: string;
38
39
  squareSmallFilled: string;
40
+ borderVertical: string;
39
41
  };
40
42
  sticker: () => import("@poppinss/cliui").Instructions;
41
43
  instructions: () => import("@poppinss/cliui").Instructions;
@@ -105,7 +107,19 @@ export declare class RoutesScanner {
105
107
  *
106
108
  * @param controllerPath - Path to the controller file to invalidate
107
109
  */
108
- invalidate(controllerPath: string): Promise<void>;
110
+ invalidate(controllerPath: string): Promise<boolean>;
111
+ /**
112
+ * Sets a filter function to selectively include routes during scanning.
113
+ *
114
+ * @param filterFn - Function that returns true for routes to include
115
+ * @returns This RoutesScanner instance for method chaining
116
+ *
117
+ * @example
118
+ * scanner.filter((route) => {
119
+ * return route.pattern.startsWith('/api')
120
+ * })
121
+ */
122
+ filter(filterFn: RoutesScannerFilterFn): this;
109
123
  /**
110
124
  * Scans an array of Route list items and fetches their validators,
111
125
  * controllers, and request/response types.