@adonisjs/assembler 8.0.0-next.2 → 8.0.0-next.20
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/README.md +88 -84
- package/build/chunk-4452KFDQ.js +465 -0
- package/build/chunk-JFBQ4OEM.js +434 -0
- package/build/chunk-NAASGAFO.js +478 -0
- package/build/chunk-TIKQQRMX.js +116 -0
- package/build/index.d.ts +3 -0
- package/build/index.js +800 -447
- package/build/src/bundler.d.ts +44 -3
- package/build/src/code_scanners/routes_scanner/main.d.ts +119 -0
- package/build/src/code_scanners/routes_scanner/main.js +8 -0
- package/build/src/code_scanners/routes_scanner/validator_extractor.d.ts +26 -0
- package/build/src/code_transformer/main.d.ts +44 -43
- package/build/src/code_transformer/main.js +123 -101
- package/build/src/code_transformer/rc_file_transformer.d.ts +56 -4
- package/build/src/debug.d.ts +12 -0
- package/build/src/dev_server.d.ts +92 -17
- package/build/src/file_buffer.d.ts +87 -0
- package/build/src/file_system.d.ts +46 -8
- package/build/src/helpers.d.ts +115 -0
- package/build/src/helpers.js +16 -0
- package/build/src/index_generator/main.d.ts +68 -0
- package/build/src/index_generator/main.js +7 -0
- package/build/src/index_generator/source.d.ts +60 -0
- package/build/src/paths_resolver.d.ts +41 -0
- package/build/src/shortcuts_manager.d.ts +43 -28
- package/build/src/test_runner.d.ts +57 -12
- package/build/src/types/code_scanners.d.ts +226 -0
- package/build/src/types/code_transformer.d.ts +61 -19
- package/build/src/types/common.d.ts +270 -51
- package/build/src/types/hooks.d.ts +235 -22
- package/build/src/types/main.d.ts +15 -1
- package/build/src/utils.d.ts +99 -15
- package/build/src/virtual_file_system.d.ts +112 -0
- package/package.json +33 -20
- package/build/chunk-RR4HCA4M.js +0 -7
package/README.md
CHANGED
|
@@ -50,17 +50,7 @@ const devServer = new DevServer(appRoot, {
|
|
|
50
50
|
pattern: 'resources/views/**/*.edge',
|
|
51
51
|
reloadServer: false,
|
|
52
52
|
}
|
|
53
|
-
]
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* The assets bundler process to start
|
|
57
|
-
*/
|
|
58
|
-
assets: {
|
|
59
|
-
enabled: true,
|
|
60
|
-
name: 'vite',
|
|
61
|
-
cmd: 'vite',
|
|
62
|
-
args: []
|
|
63
|
-
}
|
|
53
|
+
]
|
|
64
54
|
})
|
|
65
55
|
|
|
66
56
|
devServer.onError((error) => {
|
|
@@ -87,9 +77,6 @@ await devServer.start()
|
|
|
87
77
|
## Test runner
|
|
88
78
|
The `TestRunner` is used to execute the `bin/test.ts` file of your AdonisJS application. Like the `DevServer`, the `TestRunner` allows you to watch for file changes and re-run the tests. The following steps are taken to re-run tests in watch mode.
|
|
89
79
|
|
|
90
|
-
> [!NOTE]
|
|
91
|
-
> Read [Using a file watcher](#using-a-file-watcher) section to understand which files are watched by the file watcher.
|
|
92
|
-
|
|
93
80
|
- If the changed file is a test file, only tests for that file will be re-run.
|
|
94
81
|
- Otherwise, all tests will re-run with respect to the initial filters applied when running the `node ace test` command.
|
|
95
82
|
|
|
@@ -176,17 +163,6 @@ const bundler = new Bundler(appRoot, ts, {
|
|
|
176
163
|
reloadServer: false,
|
|
177
164
|
}
|
|
178
165
|
],
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* The assets bundler to use to bundle the frontend
|
|
182
|
-
* assets
|
|
183
|
-
*/
|
|
184
|
-
assets: {
|
|
185
|
-
enabled: true,
|
|
186
|
-
name: 'vite',
|
|
187
|
-
cmd: 'vite',
|
|
188
|
-
args: ['build']
|
|
189
|
-
}
|
|
190
166
|
})
|
|
191
167
|
```
|
|
192
168
|
|
|
@@ -444,83 +420,111 @@ export const policies = {
|
|
|
444
420
|
}
|
|
445
421
|
```
|
|
446
422
|
|
|
447
|
-
|
|
448
|
-
|
|
423
|
+
## Index generator
|
|
424
|
+
|
|
425
|
+
The `IndexGenerator` is a core concept in Assembler that is used to watch the filesystem and create barrel files or types from a source directory.
|
|
426
|
+
|
|
427
|
+
For example, the core of the framework uses the following config to generate controllers, events, and listeners barrel file.
|
|
449
428
|
|
|
450
429
|
```ts
|
|
451
|
-
|
|
430
|
+
import hooks from '@adonisjs/assembler/hooks'
|
|
431
|
+
|
|
432
|
+
export default hooks.init((type, parent, indexGenerator) => {
|
|
433
|
+
indexGenerator.add('controllers', {
|
|
434
|
+
source: './app/controllers',
|
|
435
|
+
importAlias: '#controllers',
|
|
436
|
+
as: 'barrelFile',
|
|
437
|
+
exportName: 'controllers',
|
|
438
|
+
removeSuffix: 'controllers',
|
|
439
|
+
output: './.adonisjs/server/controllers.ts',
|
|
440
|
+
})
|
|
452
441
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
})
|
|
442
|
+
indexGenerator.add('events', {
|
|
443
|
+
source: './app/events',
|
|
444
|
+
importAlias: '#events',
|
|
445
|
+
as: 'barrelFile',
|
|
446
|
+
exportName: 'events',
|
|
447
|
+
output: './.adonisjs/server/events.ts',
|
|
448
|
+
})
|
|
460
449
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
450
|
+
indexGenerator.add('listeners', {
|
|
451
|
+
source: './app/listeners',
|
|
452
|
+
importAlias: '#listeners',
|
|
453
|
+
as: 'barrelFile',
|
|
454
|
+
exportName: 'listeners',
|
|
455
|
+
removeSuffix: 'listener',
|
|
456
|
+
output: './.adonisjs/server/listeners.ts',
|
|
457
|
+
})
|
|
458
|
+
})
|
|
469
459
|
```
|
|
470
460
|
|
|
471
|
-
|
|
461
|
+
Once the configurations have been registered with the `IndexGenerator`, it will scan the needed directories and generate the output files. Additionally, the file watchers will re-trigger the index generation when a file is added or removed from the source directory.
|
|
472
462
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
463
|
+
### Barrel file generation
|
|
464
|
+
|
|
465
|
+
Barrel files provide a single entry point by exporting a collection of lazily imported entities, recursively gathered from a source directory. The `IndexGenerator` automates this process by scanning nested directories and generating import mappings that mirror the file structure.
|
|
466
|
+
|
|
467
|
+
For example, given the following `controllers` directory structure:
|
|
468
|
+
|
|
469
|
+
```sh
|
|
470
|
+
app/controllers/
|
|
471
|
+
├── auth/
|
|
472
|
+
│ ├── login_controller.ts
|
|
473
|
+
│ └── register_controller.ts
|
|
474
|
+
├── blog/
|
|
475
|
+
│ ├── posts_controller.ts
|
|
476
|
+
│ └── post_comments_controller.ts
|
|
477
|
+
└── users_controller.ts
|
|
482
478
|
```
|
|
483
479
|
|
|
484
|
-
|
|
480
|
+
When processed with the controllers configuration, the `IndexGenerator` produces a barrel file that reflects the directory hierarchy as nested objects, using capitalized file names as property keys.
|
|
485
481
|
|
|
486
482
|
```ts
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
importAlias: '#controllers'
|
|
492
|
-
}, {
|
|
493
|
-
destination: '.adonisjs/backend/controllers',
|
|
494
|
-
exportName: 'controllers',
|
|
495
|
-
computeBaseName(filePath, sourcePath) {
|
|
496
|
-
const baseName = relative(sourcePath, filePath)
|
|
497
|
-
return new StringBuilder(baseName).toUnixSlash().removeExtension().removeSuffix('Controller').toString()
|
|
483
|
+
export const controllers = {
|
|
484
|
+
auth: {
|
|
485
|
+
Login: () => import('#controllers/auth/login_controller'),
|
|
486
|
+
Register: () => import('#controllers/auth/register_controller'),
|
|
498
487
|
},
|
|
499
|
-
|
|
488
|
+
blog: {
|
|
489
|
+
Posts: () => import('#controllers/blog/posts_controller'),
|
|
490
|
+
PostComments: () => import('#controllers/blog/post_comments_controller'),
|
|
491
|
+
},
|
|
492
|
+
Users: () => import('#controllers/users_controller'),
|
|
493
|
+
}
|
|
500
494
|
```
|
|
501
495
|
|
|
502
|
-
|
|
503
|
-
|
|
496
|
+
### Types generation
|
|
497
|
+
|
|
498
|
+
To generate a types file, register a custom callback that takes an instance of the `VirtualFileSystem` and updates the output string via the `buffer` object.
|
|
499
|
+
|
|
500
|
+
The collection is represented as key–value pairs:
|
|
501
|
+
|
|
502
|
+
- **Key** — the relative path (without extension) from the root of the source directory.
|
|
503
|
+
- **Value** — an object containing the file's `importPath`, `relativePath`, and `absolutePath`.
|
|
504
504
|
|
|
505
505
|
```ts
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
506
|
+
import hooks from '@adonisjs/assembler/hooks'
|
|
507
|
+
|
|
508
|
+
export default hooks.init((type, parent, indexGenerator) => {
|
|
509
|
+
indexGenerator.add('inertiaPages', {
|
|
510
|
+
source: './inertia/pages',
|
|
511
|
+
as: (vfs, buffer) => {
|
|
512
|
+
buffer.write(`declare module '@adonisjs/inertia' {`).indent()
|
|
513
|
+
buffer.write(`export interface Pages {`).indent()
|
|
514
|
+
|
|
515
|
+
const files = vfs.asList()
|
|
516
|
+
Object.keys(files).forEach((filePath) => {
|
|
517
|
+
buffer.write(
|
|
518
|
+
`'${filePath}': InferPageProps<typeof import('${file.importPath}').default>`
|
|
518
519
|
)
|
|
519
|
-
|
|
520
|
-
|
|
520
|
+
})
|
|
521
|
+
|
|
522
|
+
buffer.dedent().write('}')
|
|
523
|
+
buffer.dedent().write('}')
|
|
521
524
|
},
|
|
522
|
-
|
|
523
|
-
)
|
|
525
|
+
output: './.adonisjs/server/inertia_pages.d.ts',
|
|
526
|
+
})
|
|
527
|
+
})
|
|
524
528
|
```
|
|
525
529
|
|
|
526
530
|
## Contributing
|
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VirtualFileSystem,
|
|
3
|
+
debug_default,
|
|
4
|
+
removeExtension,
|
|
5
|
+
throttle
|
|
6
|
+
} from "./chunk-JFBQ4OEM.js";
|
|
7
|
+
|
|
8
|
+
// src/index_generator/source.ts
|
|
9
|
+
import string from "@poppinss/utils/string";
|
|
10
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
11
|
+
import { dirname, join, relative } from "path/posix";
|
|
12
|
+
import StringBuilder from "@poppinss/utils/string_builder";
|
|
13
|
+
|
|
14
|
+
// src/file_buffer.ts
|
|
15
|
+
var FileBuffer = class _FileBuffer {
|
|
16
|
+
/**
|
|
17
|
+
* Whether to add an end-of-line character at the end of the output
|
|
18
|
+
*/
|
|
19
|
+
#eol = false;
|
|
20
|
+
/**
|
|
21
|
+
* Collected lines
|
|
22
|
+
*/
|
|
23
|
+
#buffer = [];
|
|
24
|
+
/**
|
|
25
|
+
* Current indentation size. Each call to indent will increment
|
|
26
|
+
* it by 2
|
|
27
|
+
*/
|
|
28
|
+
#identationSize = 0;
|
|
29
|
+
/**
|
|
30
|
+
* Cached compiled output. Once this value is set, the `flush`
|
|
31
|
+
* method will become a noop
|
|
32
|
+
*/
|
|
33
|
+
#compiledOutput;
|
|
34
|
+
/**
|
|
35
|
+
* Creates a new child buffer instance
|
|
36
|
+
*
|
|
37
|
+
* @returns A new FileBuffer instance
|
|
38
|
+
*/
|
|
39
|
+
create() {
|
|
40
|
+
return new _FileBuffer();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Returns the size of buffer text
|
|
44
|
+
*
|
|
45
|
+
* @returns The number of lines in the buffer
|
|
46
|
+
*/
|
|
47
|
+
get size() {
|
|
48
|
+
return this.#buffer.length;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Enable or disable end-of-line character at the end of output
|
|
52
|
+
*
|
|
53
|
+
* @param enabled - Whether to add EOL character
|
|
54
|
+
* @returns This FileBuffer instance for method chaining
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* const buffer = new FileBuffer()
|
|
58
|
+
* buffer.eol(true).writeLine('Hello').flush() // 'Hello\n\n'
|
|
59
|
+
*/
|
|
60
|
+
eol(enabled) {
|
|
61
|
+
this.#eol = enabled;
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Write a new line to the output with current indentation
|
|
66
|
+
*
|
|
67
|
+
* @param text - The text to write as a new line
|
|
68
|
+
* @returns This FileBuffer instance for method chaining
|
|
69
|
+
*/
|
|
70
|
+
writeLine(text) {
|
|
71
|
+
if (typeof text === "string") {
|
|
72
|
+
this.#buffer.push(`${" ".repeat(this.#identationSize)}${text}
|
|
73
|
+
`);
|
|
74
|
+
} else {
|
|
75
|
+
this.#buffer.push(text);
|
|
76
|
+
this.#buffer.push("");
|
|
77
|
+
}
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Write text to the output without adding a new line
|
|
82
|
+
*
|
|
83
|
+
* @param text - The text to write without a newline
|
|
84
|
+
* @returns This FileBuffer instance for method chaining
|
|
85
|
+
*/
|
|
86
|
+
write(text) {
|
|
87
|
+
if (typeof text === "string") {
|
|
88
|
+
this.#buffer.push(`${" ".repeat(this.#identationSize)}${text}`);
|
|
89
|
+
} else {
|
|
90
|
+
this.#buffer.push(text);
|
|
91
|
+
}
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Increase indentation by 2 spaces
|
|
96
|
+
*
|
|
97
|
+
* @returns This FileBuffer instance for method chaining
|
|
98
|
+
*/
|
|
99
|
+
indent() {
|
|
100
|
+
this.#identationSize += 2;
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Decrease indentation by 2 spaces (minimum of 0)
|
|
105
|
+
*
|
|
106
|
+
* @returns This FileBuffer instance for method chaining
|
|
107
|
+
*/
|
|
108
|
+
dedent() {
|
|
109
|
+
this.#identationSize -= 2;
|
|
110
|
+
if (this.#identationSize < 0) {
|
|
111
|
+
this.#identationSize = 0;
|
|
112
|
+
}
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Convert the buffer to a string representation
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* const buffer = new FileBuffer()
|
|
120
|
+
* buffer.writeLine('Hello')
|
|
121
|
+
* console.log(buffer.toString())
|
|
122
|
+
*/
|
|
123
|
+
toString() {
|
|
124
|
+
return this.flush();
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Return template as a string, joining all buffer lines
|
|
128
|
+
*
|
|
129
|
+
* Once called, the output is cached and subsequent calls return the same result.
|
|
130
|
+
* The flush method becomes a no-op after the first call.
|
|
131
|
+
*
|
|
132
|
+
* @returns The complete buffer content as a string
|
|
133
|
+
*/
|
|
134
|
+
flush() {
|
|
135
|
+
if (this.#compiledOutput !== void 0) {
|
|
136
|
+
return this.#compiledOutput;
|
|
137
|
+
}
|
|
138
|
+
this.#compiledOutput = this.#buffer.join("\n");
|
|
139
|
+
return this.#eol ? `${this.#compiledOutput}
|
|
140
|
+
` : this.#compiledOutput;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// src/index_generator/source.ts
|
|
145
|
+
var IndexGeneratorSource = class {
|
|
146
|
+
/**
|
|
147
|
+
* The application root directory path
|
|
148
|
+
*/
|
|
149
|
+
#appRoot;
|
|
150
|
+
/**
|
|
151
|
+
* The absolute path to the output file
|
|
152
|
+
*/
|
|
153
|
+
#output;
|
|
154
|
+
/**
|
|
155
|
+
* The absolute path to the source directory
|
|
156
|
+
*/
|
|
157
|
+
#source;
|
|
158
|
+
/**
|
|
159
|
+
* The directory containing the output file
|
|
160
|
+
*/
|
|
161
|
+
#outputDirname;
|
|
162
|
+
/**
|
|
163
|
+
* Virtual file system for scanning source files
|
|
164
|
+
*/
|
|
165
|
+
#vfs;
|
|
166
|
+
/**
|
|
167
|
+
* Configuration for this index generator source
|
|
168
|
+
*/
|
|
169
|
+
#config;
|
|
170
|
+
/**
|
|
171
|
+
* CLI logger instance for output messages
|
|
172
|
+
*/
|
|
173
|
+
#cliLogger;
|
|
174
|
+
/**
|
|
175
|
+
* Generate the output content and write it to the output file
|
|
176
|
+
*
|
|
177
|
+
* This method creates the file buffer, populates it with the generated
|
|
178
|
+
* content based on configuration, and writes it to disk.
|
|
179
|
+
*/
|
|
180
|
+
#generateOutput = throttle(async () => {
|
|
181
|
+
const buffer = new FileBuffer().eol(true);
|
|
182
|
+
if (this.#config.as === "barrelFile") {
|
|
183
|
+
this.#asBarrelFile(
|
|
184
|
+
this.#vfs,
|
|
185
|
+
buffer,
|
|
186
|
+
this.#config.exportName,
|
|
187
|
+
this.#config.disableLazyImports
|
|
188
|
+
);
|
|
189
|
+
} else {
|
|
190
|
+
this.#config.as(this.#vfs, buffer, this.#config, {
|
|
191
|
+
toImportPath: this.#createBarrelFileImportGenerator(
|
|
192
|
+
this.#source,
|
|
193
|
+
this.#outputDirname,
|
|
194
|
+
this.#config
|
|
195
|
+
)
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
await mkdir(dirname(this.#output), { recursive: true });
|
|
199
|
+
await writeFile(this.#output, buffer.flush());
|
|
200
|
+
});
|
|
201
|
+
/**
|
|
202
|
+
* Unique name for this index generator source
|
|
203
|
+
*/
|
|
204
|
+
name;
|
|
205
|
+
/**
|
|
206
|
+
* Create a new IndexGeneratorSource instance
|
|
207
|
+
*
|
|
208
|
+
* @param name - Unique name for this index generator source
|
|
209
|
+
* @param appRoot - The application root directory path
|
|
210
|
+
* @param cliLogger - Logger instance for CLI output
|
|
211
|
+
* @param config - Configuration for this index generator source
|
|
212
|
+
*/
|
|
213
|
+
constructor(name, appRoot, cliLogger, config) {
|
|
214
|
+
this.name = name;
|
|
215
|
+
this.#config = config;
|
|
216
|
+
this.#appRoot = appRoot;
|
|
217
|
+
this.#cliLogger = cliLogger;
|
|
218
|
+
this.#source = join(this.#appRoot, this.#config.source);
|
|
219
|
+
this.#output = join(this.#appRoot, this.#config.output);
|
|
220
|
+
this.#outputDirname = dirname(this.#output);
|
|
221
|
+
this.#vfs = new VirtualFileSystem(this.#source, {
|
|
222
|
+
glob: this.#config.glob
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Converts a recursive file tree to a string representation
|
|
227
|
+
*
|
|
228
|
+
* This method recursively processes a file tree structure and writes
|
|
229
|
+
* it as JavaScript object notation to the provided buffer.
|
|
230
|
+
*
|
|
231
|
+
* @param input - The recursive file tree to convert
|
|
232
|
+
* @param buffer - The file buffer to write the output to
|
|
233
|
+
*/
|
|
234
|
+
#treeToString(input, buffer) {
|
|
235
|
+
Object.keys(input).forEach((key) => {
|
|
236
|
+
const value = input[key];
|
|
237
|
+
if (typeof value === "string") {
|
|
238
|
+
buffer.write(`${key}: ${value},`);
|
|
239
|
+
} else {
|
|
240
|
+
buffer.write(`${key}: {`).indent();
|
|
241
|
+
this.#treeToString(value, buffer);
|
|
242
|
+
buffer.dedent().write(`},`);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Transforms the barrel file index key. Converts basename to PascalCase
|
|
248
|
+
* and all other paths to camelCase
|
|
249
|
+
*
|
|
250
|
+
* @param config - Configuration containing suffix removal options
|
|
251
|
+
* @returns Function that transforms file paths to appropriate keys
|
|
252
|
+
*/
|
|
253
|
+
#createBarrelFileKeyGenerator(config) {
|
|
254
|
+
return function(key) {
|
|
255
|
+
const paths = key.split("/");
|
|
256
|
+
let baseName = new StringBuilder(paths.pop());
|
|
257
|
+
if (config.computeBaseName) {
|
|
258
|
+
baseName = config.computeBaseName(baseName);
|
|
259
|
+
} else {
|
|
260
|
+
baseName = baseName.removeSuffix(config.removeSuffix ?? "").pascalCase();
|
|
261
|
+
}
|
|
262
|
+
return [...paths.map((p) => string.camelCase(p)), baseName.toString()].join("/");
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Converts the file path to a lazy import. In case of an alias, the source
|
|
267
|
+
* path is replaced with the alias, otherwise a relative import is created
|
|
268
|
+
* from the output dirname.
|
|
269
|
+
*
|
|
270
|
+
* @param source - The source directory path
|
|
271
|
+
* @param outputDirname - The output directory path
|
|
272
|
+
* @param config - Configuration containing import alias options
|
|
273
|
+
* @returns Function that converts file paths to import statements
|
|
274
|
+
*/
|
|
275
|
+
#createBarrelFileImportGenerator(source, outputDirname, config) {
|
|
276
|
+
return function(filePath) {
|
|
277
|
+
if (config.importAlias) {
|
|
278
|
+
debug_default('converting "%s" to import alias, source "%s"', filePath, source);
|
|
279
|
+
return removeExtension(filePath.replace(source, config.importAlias));
|
|
280
|
+
}
|
|
281
|
+
debug_default('converting "%s" to relative import, source "%s"', filePath, outputDirname);
|
|
282
|
+
return relative(outputDirname, filePath);
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Generate a barrel file export structure
|
|
287
|
+
*
|
|
288
|
+
* This method creates a nested object structure that represents all
|
|
289
|
+
* discovered files as lazy imports, organized by directory structure.
|
|
290
|
+
*
|
|
291
|
+
* @param vfs - Virtual file system containing the scanned files
|
|
292
|
+
* @param buffer - File buffer to write the barrel exports to
|
|
293
|
+
* @param exportName - Name for the main export object
|
|
294
|
+
*/
|
|
295
|
+
#asBarrelFile(vfs, buffer, exportName, disableLazyImports) {
|
|
296
|
+
const useEagerImports = disableLazyImports === true ? true : false;
|
|
297
|
+
const keyGenerator = this.#createBarrelFileKeyGenerator(this.#config);
|
|
298
|
+
const importsBuffer = buffer.create();
|
|
299
|
+
const importGenerator = this.#createBarrelFileImportGenerator(
|
|
300
|
+
this.#source,
|
|
301
|
+
this.#outputDirname,
|
|
302
|
+
this.#config
|
|
303
|
+
);
|
|
304
|
+
const tree = vfs.asTree({
|
|
305
|
+
transformKey: keyGenerator,
|
|
306
|
+
transformValue: (filePath, key) => {
|
|
307
|
+
if (useEagerImports) {
|
|
308
|
+
const importKey = new StringBuilder(key).pascalCase().toString();
|
|
309
|
+
importsBuffer.write(`import ${importKey} from '${importGenerator(filePath)}'`);
|
|
310
|
+
return importKey;
|
|
311
|
+
}
|
|
312
|
+
return `() => import('${importGenerator(filePath)}')`;
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
const treeLength = Object.keys(tree).length;
|
|
316
|
+
if (!treeLength) {
|
|
317
|
+
buffer.write(`export const ${exportName} = {}`);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (useEagerImports) {
|
|
321
|
+
buffer.writeLine(importsBuffer);
|
|
322
|
+
}
|
|
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
|
+
const added = this.#vfs.add(filePath);
|
|
348
|
+
if (added) {
|
|
349
|
+
debug_default('file added, re-generating "%s" index', this.name);
|
|
350
|
+
const startTime = process.hrtime();
|
|
351
|
+
await this.#generateOutput();
|
|
352
|
+
this.#logCreation(startTime);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Remove a file from the virtual file system and regenerate index if needed
|
|
357
|
+
*
|
|
358
|
+
* If the file was previously tracked, it will be removed from the
|
|
359
|
+
* virtual file system and the index file will be regenerated.
|
|
360
|
+
*
|
|
361
|
+
* @param filePath - Absolute path of the file to remove
|
|
362
|
+
*/
|
|
363
|
+
async removeFile(filePath) {
|
|
364
|
+
const removed = this.#vfs.remove(filePath);
|
|
365
|
+
if (removed) {
|
|
366
|
+
debug_default('file removed, re-generating "%s" index', this.name);
|
|
367
|
+
const startTime = process.hrtime();
|
|
368
|
+
await this.#generateOutput();
|
|
369
|
+
this.#logCreation(startTime);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Generate the index file
|
|
374
|
+
*
|
|
375
|
+
* This method scans the source directory, processes files according to
|
|
376
|
+
* the configuration, and writes the generated index file to disk.
|
|
377
|
+
*/
|
|
378
|
+
async generate() {
|
|
379
|
+
const startTime = process.hrtime();
|
|
380
|
+
await this.#vfs.scan();
|
|
381
|
+
await this.#generateOutput();
|
|
382
|
+
this.#logCreation(startTime);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
// src/index_generator/main.ts
|
|
387
|
+
var IndexGenerator = class {
|
|
388
|
+
/**
|
|
389
|
+
* The application root directory path
|
|
390
|
+
*/
|
|
391
|
+
appRoot;
|
|
392
|
+
/**
|
|
393
|
+
* Collection of registered index generator sources
|
|
394
|
+
*/
|
|
395
|
+
#sources = {};
|
|
396
|
+
#cliLogger;
|
|
397
|
+
/**
|
|
398
|
+
* Create a new IndexGenerator instance
|
|
399
|
+
*
|
|
400
|
+
* @param appRoot - The application root directory path
|
|
401
|
+
* @param cliLogger - Logger instance for CLI output
|
|
402
|
+
*/
|
|
403
|
+
constructor(appRoot, cliLogger) {
|
|
404
|
+
this.appRoot = appRoot;
|
|
405
|
+
this.#cliLogger = cliLogger;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Add a new index generator source
|
|
409
|
+
*
|
|
410
|
+
* @param name - Unique name for the source
|
|
411
|
+
* @param config - Configuration for the index generator source
|
|
412
|
+
* @returns This IndexGenerator instance for method chaining
|
|
413
|
+
*/
|
|
414
|
+
add(name, config) {
|
|
415
|
+
this.#sources[name] = new IndexGeneratorSource(name, this.appRoot, this.#cliLogger, config);
|
|
416
|
+
return this;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Add a file to all registered index generator sources
|
|
420
|
+
*
|
|
421
|
+
* This method propagates the file addition to all registered sources,
|
|
422
|
+
* allowing them to regenerate their index files if the new file matches
|
|
423
|
+
* their glob patterns.
|
|
424
|
+
*
|
|
425
|
+
* @param filePath - Absolute path of the file to add
|
|
426
|
+
*/
|
|
427
|
+
async addFile(filePath) {
|
|
428
|
+
const sources = Object.values(this.#sources);
|
|
429
|
+
for (let source of sources) {
|
|
430
|
+
await source.addFile(filePath);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Remove a file from all registered index generator sources
|
|
435
|
+
*
|
|
436
|
+
* This method propagates the file removal to all registered sources,
|
|
437
|
+
* allowing them to regenerate their index files if the removed file
|
|
438
|
+
* was previously tracked.
|
|
439
|
+
*
|
|
440
|
+
* @param filePath - Absolute path of the file to remove
|
|
441
|
+
*/
|
|
442
|
+
async removeFile(filePath) {
|
|
443
|
+
const sources = Object.values(this.#sources);
|
|
444
|
+
for (let source of sources) {
|
|
445
|
+
await source.removeFile(filePath);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Generate all registered index files
|
|
450
|
+
*
|
|
451
|
+
* Iterates through all registered sources and generates their
|
|
452
|
+
* corresponding index files.
|
|
453
|
+
*/
|
|
454
|
+
async generate() {
|
|
455
|
+
const sources = Object.values(this.#sources);
|
|
456
|
+
for (let source of sources) {
|
|
457
|
+
await source.generate();
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
export {
|
|
463
|
+
FileBuffer,
|
|
464
|
+
IndexGenerator
|
|
465
|
+
};
|