@adonisjs/assembler 8.0.0-next.9 → 8.0.0
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 +260 -0
- package/build/codemod_exception-CzQgXAAf.js +137 -0
- package/build/index.d.ts +1 -1
- package/build/index.js +927 -1724
- package/build/source-dVeugJ0e.js +166 -0
- package/build/src/bundler.d.ts +2 -0
- package/build/src/code_scanners/routes_scanner/main.d.ts +16 -2
- package/build/src/code_scanners/routes_scanner/main.js +168 -441
- package/build/src/code_transformer/main.d.ts +14 -1
- package/build/src/code_transformer/main.js +502 -622
- package/build/src/code_transformer/rc_file_transformer.d.ts +28 -2
- package/build/src/debug.d.ts +1 -1
- package/build/src/dev_server.d.ts +60 -12
- package/build/src/exceptions/codemod_exception.d.ts +178 -0
- package/build/src/file_buffer.d.ts +19 -0
- package/build/src/file_system.d.ts +2 -2
- package/build/src/helpers.js +72 -16
- package/build/src/index_generator/main.js +28 -6
- package/build/src/paths_resolver.d.ts +2 -1
- package/build/src/test_runner.d.ts +3 -2
- package/build/src/types/code_scanners.d.ts +29 -13
- package/build/src/types/code_transformer.d.ts +127 -0
- package/build/src/types/common.d.ts +98 -2
- package/build/src/types/hooks.d.ts +4 -1
- package/build/src/types/main.js +1 -0
- package/build/src/utils.d.ts +9 -3
- package/build/src/virtual_file_system.d.ts +1 -1
- package/build/validator_extractor-Ccio_Ndi.js +82 -0
- package/build/virtual_file_system-bGeoWsK-.js +285 -0
- package/package.json +41 -39
- package/build/chunk-7XU453QB.js +0 -418
- package/build/chunk-PORDZS62.js +0 -391
- package/build/chunk-TIKQQRMX.js +0 -116
- package/build/src/hooks.d.ts +0 -224
package/build/index.js
CHANGED
|
@@ -1,376 +1,94 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
copyFiles,
|
|
8
|
-
debug_default,
|
|
9
|
-
getPort,
|
|
10
|
-
loadHooks,
|
|
11
|
-
memoize,
|
|
12
|
-
parseConfig,
|
|
13
|
-
run,
|
|
14
|
-
runNode,
|
|
15
|
-
throttle,
|
|
16
|
-
watch
|
|
17
|
-
} from "./chunk-PORDZS62.js";
|
|
18
|
-
|
|
19
|
-
// src/hooks.ts
|
|
20
|
-
var hooks = {
|
|
21
|
-
/**
|
|
22
|
-
* Hook called during application initialization. This is the first hook
|
|
23
|
-
* that gets executed when the assembler starts up.
|
|
24
|
-
*
|
|
25
|
-
* @param callback - Function to execute when the init event occurs
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```js
|
|
29
|
-
* hooks.init((app) => {
|
|
30
|
-
* console.log('Application is initializing')
|
|
31
|
-
* // Setup global configurations
|
|
32
|
-
* })
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
init(callback) {
|
|
36
|
-
return callback;
|
|
37
|
-
},
|
|
38
|
-
/**
|
|
39
|
-
* Hook called after routes have been committed to the router.
|
|
40
|
-
* This occurs after all route definitions have been processed.
|
|
41
|
-
*
|
|
42
|
-
* @param callback - Function to execute when routes are committed
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* ```js
|
|
46
|
-
* hooks.routesCommitted((router) => {
|
|
47
|
-
* console.log('All routes have been committed to the router')
|
|
48
|
-
* // Perform route-based setup
|
|
49
|
-
* })
|
|
50
|
-
* ```
|
|
51
|
-
*/
|
|
52
|
-
routesCommitted(callback) {
|
|
53
|
-
return callback;
|
|
54
|
-
},
|
|
55
|
-
/**
|
|
56
|
-
* Hook called when the assembler starts scanning for route files.
|
|
57
|
-
* This happens before any route files are actually processed.
|
|
58
|
-
*
|
|
59
|
-
* @param callback - Function to execute when route scanning begins
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* ```js
|
|
63
|
-
* hooks.routesScanning(() => {
|
|
64
|
-
* console.log('Starting to scan for route files')
|
|
65
|
-
* // Setup route scanning configurations
|
|
66
|
-
* })
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
|
-
routesScanning(callback) {
|
|
70
|
-
return callback;
|
|
71
|
-
},
|
|
72
|
-
/**
|
|
73
|
-
* Hook called after all route files have been scanned and processed.
|
|
74
|
-
* This occurs once the route scanning phase is complete.
|
|
75
|
-
*
|
|
76
|
-
* @param callback - Function to execute when route scanning is finished
|
|
77
|
-
*
|
|
78
|
-
* @example
|
|
79
|
-
* ```js
|
|
80
|
-
* hooks.routesScanned((scannedRoutes) => {
|
|
81
|
-
* console.log('Route scanning completed')
|
|
82
|
-
* // Process scanned route information
|
|
83
|
-
* })
|
|
84
|
-
* ```
|
|
85
|
-
*/
|
|
86
|
-
routesScanned(callback) {
|
|
87
|
-
return callback;
|
|
88
|
-
},
|
|
89
|
-
/**
|
|
90
|
-
* Hook called when a file is modified during development.
|
|
91
|
-
* This is triggered by the file watcher when changes are detected.
|
|
92
|
-
*
|
|
93
|
-
* @param callback - Function to execute when a file changes
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* ```js
|
|
97
|
-
* hooks.fileChanged((filePath, stats) => {
|
|
98
|
-
* console.log(`File changed: ${filePath}`)
|
|
99
|
-
* // Handle file change logic
|
|
100
|
-
* })
|
|
101
|
-
* ```
|
|
102
|
-
*/
|
|
103
|
-
fileChanged(callback) {
|
|
104
|
-
return callback;
|
|
105
|
-
},
|
|
106
|
-
/**
|
|
107
|
-
* Hook called when a new file is added during development.
|
|
108
|
-
* This is triggered by the file watcher when new files are created.
|
|
109
|
-
*
|
|
110
|
-
* @param callback - Function to execute when a file is added
|
|
111
|
-
*
|
|
112
|
-
* @example
|
|
113
|
-
* ```js
|
|
114
|
-
* hooks.fileAdded((filePath, stats) => {
|
|
115
|
-
* console.log(`New file added: ${filePath}`)
|
|
116
|
-
* // Handle new file logic
|
|
117
|
-
* })
|
|
118
|
-
* ```
|
|
119
|
-
*/
|
|
120
|
-
fileAdded(callback) {
|
|
121
|
-
return callback;
|
|
122
|
-
},
|
|
123
|
-
/**
|
|
124
|
-
* Hook called when a file is removed during development.
|
|
125
|
-
* This is triggered by the file watcher when files are deleted.
|
|
126
|
-
*
|
|
127
|
-
* @param callback - Function to execute when a file is removed
|
|
128
|
-
*
|
|
129
|
-
* @example
|
|
130
|
-
* ```js
|
|
131
|
-
* hooks.fileRemoved((filePath) => {
|
|
132
|
-
* console.log(`File removed: ${filePath}`)
|
|
133
|
-
* // Handle file removal logic
|
|
134
|
-
* })
|
|
135
|
-
* ```
|
|
136
|
-
*/
|
|
137
|
-
fileRemoved(callback) {
|
|
138
|
-
return callback;
|
|
139
|
-
},
|
|
140
|
-
/**
|
|
141
|
-
* Hook called when the development server is about to start.
|
|
142
|
-
* This occurs before the server begins listening for connections.
|
|
143
|
-
*
|
|
144
|
-
* @param callback - Function to execute when dev server is starting
|
|
145
|
-
*
|
|
146
|
-
* @example
|
|
147
|
-
* ```js
|
|
148
|
-
* hooks.devServerStarting((server) => {
|
|
149
|
-
* console.log('Development server is starting')
|
|
150
|
-
* // Setup server configurations
|
|
151
|
-
* })
|
|
152
|
-
* ```
|
|
153
|
-
*/
|
|
154
|
-
devServerStarting(callback) {
|
|
155
|
-
return callback;
|
|
156
|
-
},
|
|
157
|
-
/**
|
|
158
|
-
* Hook called after the development server has successfully started.
|
|
159
|
-
* This occurs once the server is listening and ready to accept requests.
|
|
160
|
-
*
|
|
161
|
-
* @param callback - Function to execute when dev server has started
|
|
162
|
-
*
|
|
163
|
-
* @example
|
|
164
|
-
* ```js
|
|
165
|
-
* hooks.devServerStarted((server) => {
|
|
166
|
-
* console.log(`Development server started on port ${server.port}`)
|
|
167
|
-
* // Notify external services or open browser
|
|
168
|
-
* })
|
|
169
|
-
* ```
|
|
170
|
-
*/
|
|
171
|
-
devServerStarted(callback) {
|
|
172
|
-
return callback;
|
|
173
|
-
},
|
|
174
|
-
/**
|
|
175
|
-
* Hook called when the build process is about to start.
|
|
176
|
-
* This occurs before any build tasks are executed.
|
|
177
|
-
*
|
|
178
|
-
* @param callback - Function to execute when build is starting
|
|
179
|
-
*
|
|
180
|
-
* @example
|
|
181
|
-
* ```js
|
|
182
|
-
* hooks.buildStarting((buildConfig) => {
|
|
183
|
-
* console.log('Build process is starting')
|
|
184
|
-
* // Setup build configurations or clean directories
|
|
185
|
-
* })
|
|
186
|
-
* ```
|
|
187
|
-
*/
|
|
188
|
-
buildStarting(callback) {
|
|
189
|
-
return callback;
|
|
190
|
-
},
|
|
191
|
-
/**
|
|
192
|
-
* Hook called after the build process has completed.
|
|
193
|
-
* This occurs once all build tasks have finished executing.
|
|
194
|
-
*
|
|
195
|
-
* @param callback - Function to execute when build is finished
|
|
196
|
-
*
|
|
197
|
-
* @example
|
|
198
|
-
* ```js
|
|
199
|
-
* hooks.buildFinished((buildResult) => {
|
|
200
|
-
* console.log('Build process completed')
|
|
201
|
-
* // Deploy artifacts or notify build completion
|
|
202
|
-
* })
|
|
203
|
-
* ```
|
|
204
|
-
*/
|
|
205
|
-
buildFinished(callback) {
|
|
206
|
-
return callback;
|
|
207
|
-
},
|
|
208
|
-
/**
|
|
209
|
-
* Hook called when the test suite is about to start.
|
|
210
|
-
* This occurs before any test files are executed.
|
|
211
|
-
*
|
|
212
|
-
* @param callback - Function to execute when tests are starting
|
|
213
|
-
*
|
|
214
|
-
* @example
|
|
215
|
-
* ```js
|
|
216
|
-
* hooks.testsStarting((testConfig) => {
|
|
217
|
-
* console.log('Test suite is starting')
|
|
218
|
-
* // Setup test database or mock services
|
|
219
|
-
* })
|
|
220
|
-
* ```
|
|
221
|
-
*/
|
|
222
|
-
testsStarting(callback) {
|
|
223
|
-
return callback;
|
|
224
|
-
},
|
|
225
|
-
/**
|
|
226
|
-
* Hook called after the test suite has completed.
|
|
227
|
-
* This occurs once all test files have finished executing.
|
|
228
|
-
*
|
|
229
|
-
* @param callback - Function to execute when tests are finished
|
|
230
|
-
*
|
|
231
|
-
* @example
|
|
232
|
-
* ```js
|
|
233
|
-
* hooks.testsFinished((testResults) => {
|
|
234
|
-
* console.log('Test suite completed')
|
|
235
|
-
* // Generate test reports or cleanup test resources
|
|
236
|
-
* })
|
|
237
|
-
* ```
|
|
238
|
-
*/
|
|
239
|
-
testsFinished(callback) {
|
|
240
|
-
return callback;
|
|
241
|
-
}
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
// src/bundler.ts
|
|
1
|
+
import { a as loadHooks, c as readTsConfig, d as runNode, f as throttle, m as debug_default, n as copyFiles, o as memoize, p as watch, r as getPort, s as parseConfig, t as VirtualFileSystem, u as run } from "./virtual_file_system-bGeoWsK-.js";
|
|
2
|
+
import { n as FileBuffer } from "./source-dVeugJ0e.js";
|
|
3
|
+
import { IndexGenerator } from "./src/index_generator/main.js";
|
|
4
|
+
import "./validator_extractor-Ccio_Ndi.js";
|
|
5
|
+
import { RoutesScanner } from "./src/code_scanners/routes_scanner/main.js";
|
|
6
|
+
import { t as CodemodException } from "./codemod_exception-CzQgXAAf.js";
|
|
245
7
|
import dedent from "dedent";
|
|
246
|
-
import fs from "fs/promises";
|
|
8
|
+
import fs, { readFile, unlink } from "node:fs/promises";
|
|
247
9
|
import { cliui } from "@poppinss/cliui";
|
|
248
|
-
import { fileURLToPath } from "url";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
249
11
|
import string from "@poppinss/utils/string";
|
|
250
|
-
import { join, relative } from "path/posix";
|
|
12
|
+
import { join, relative } from "node:path/posix";
|
|
251
13
|
import { detectPackageManager } from "@antfu/install-pkg";
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
14
|
+
import getRandomPort from "get-port";
|
|
15
|
+
import picomatch from "picomatch";
|
|
16
|
+
import prettyHrtime from "pretty-hrtime";
|
|
17
|
+
import { RuntimeException } from "@poppinss/utils/exception";
|
|
18
|
+
const SUPPORTED_PACKAGE_MANAGERS = {
|
|
19
|
+
"npm": {
|
|
20
|
+
packageManagerFiles: ["package-lock.json"],
|
|
21
|
+
installCommand: "npm ci --omit=\"dev\""
|
|
22
|
+
},
|
|
23
|
+
"yarn": {
|
|
24
|
+
packageManagerFiles: ["yarn.lock"],
|
|
25
|
+
installCommand: "yarn install --production"
|
|
26
|
+
},
|
|
27
|
+
"yarn@berry": {
|
|
28
|
+
packageManagerFiles: [
|
|
29
|
+
"yarn.lock",
|
|
30
|
+
".yarn/**/*",
|
|
31
|
+
".yarnrc.yml"
|
|
32
|
+
],
|
|
33
|
+
installCommand: "yarn workspaces focus --production"
|
|
34
|
+
},
|
|
35
|
+
"pnpm": {
|
|
36
|
+
packageManagerFiles: ["pnpm-lock.yaml"],
|
|
37
|
+
installCommand: "pnpm i --prod"
|
|
38
|
+
},
|
|
39
|
+
"bun": {
|
|
40
|
+
packageManagerFiles: ["bun.lockb"],
|
|
41
|
+
installCommand: "bun install --production"
|
|
42
|
+
}
|
|
273
43
|
};
|
|
274
44
|
var Bundler = class {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* Cleans up the build directory
|
|
325
|
-
*/
|
|
326
|
-
async #cleanupBuildDirectory(outDir) {
|
|
327
|
-
await fs.rm(outDir, { recursive: true, force: true, maxRetries: 5 });
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Runs tsc command to build the source.
|
|
331
|
-
*/
|
|
332
|
-
async #runTsc(outDir) {
|
|
333
|
-
try {
|
|
334
|
-
await run(this.cwd, {
|
|
335
|
-
stdio: "inherit",
|
|
336
|
-
script: "tsc",
|
|
337
|
-
scriptArgs: ["--outDir", outDir]
|
|
338
|
-
});
|
|
339
|
-
return true;
|
|
340
|
-
} catch {
|
|
341
|
-
return false;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
/**
|
|
345
|
-
* Copy meta files to the output directory
|
|
346
|
-
*/
|
|
347
|
-
async #copyMetaFiles(outDir, additionalFilesToCopy) {
|
|
348
|
-
const metaFiles = (this.options.metaFiles || []).map((file) => file.pattern).concat(additionalFilesToCopy);
|
|
349
|
-
await copyFiles(metaFiles, this.cwdPath, outDir);
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Detect the package manager used by the project
|
|
353
|
-
*/
|
|
354
|
-
async #detectPackageManager() {
|
|
355
|
-
const pkgManager = await detectPackageManager(this.cwdPath);
|
|
356
|
-
if (pkgManager === "deno") {
|
|
357
|
-
return "npm";
|
|
358
|
-
}
|
|
359
|
-
if (pkgManager === "pnpm@6") {
|
|
360
|
-
return "pnpm";
|
|
361
|
-
}
|
|
362
|
-
return pkgManager;
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Rewrite the ace file since the original one
|
|
366
|
-
* is importing ts-node which is not installed
|
|
367
|
-
* in a production environment.
|
|
368
|
-
*/
|
|
369
|
-
async #createAceFile(outDir) {
|
|
370
|
-
const aceFileLocation = join(outDir, "ace.js");
|
|
371
|
-
const aceFileContent = dedent(
|
|
372
|
-
/* JavaScript */
|
|
373
|
-
`
|
|
45
|
+
#ts;
|
|
46
|
+
#hooks;
|
|
47
|
+
#indexGenerator;
|
|
48
|
+
ui = cliui();
|
|
49
|
+
cwd;
|
|
50
|
+
cwdPath;
|
|
51
|
+
options;
|
|
52
|
+
constructor(cwd, ts, options) {
|
|
53
|
+
this.cwd = cwd;
|
|
54
|
+
this.options = options;
|
|
55
|
+
this.cwdPath = string.toUnixSlash(fileURLToPath(this.cwd));
|
|
56
|
+
this.#ts = ts;
|
|
57
|
+
}
|
|
58
|
+
#getRelativeName(filePath) {
|
|
59
|
+
return string.toUnixSlash(relative(this.cwdPath, filePath));
|
|
60
|
+
}
|
|
61
|
+
async #cleanupBuildDirectory(outDir) {
|
|
62
|
+
await fs.rm(outDir, {
|
|
63
|
+
recursive: true,
|
|
64
|
+
force: true,
|
|
65
|
+
maxRetries: 5
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
async #runTsc(outDir) {
|
|
69
|
+
try {
|
|
70
|
+
await run(this.cwd, {
|
|
71
|
+
stdio: "inherit",
|
|
72
|
+
script: "tsc",
|
|
73
|
+
scriptArgs: ["--outDir", outDir]
|
|
74
|
+
});
|
|
75
|
+
return true;
|
|
76
|
+
} catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async #copyMetaFiles(outDir, additionalFilesToCopy) {
|
|
81
|
+
await copyFiles((this.options.metaFiles || []).map((file) => file.pattern).concat(additionalFilesToCopy), this.cwdPath, outDir);
|
|
82
|
+
}
|
|
83
|
+
async #detectPackageManager() {
|
|
84
|
+
const pkgManager = await detectPackageManager(this.cwdPath);
|
|
85
|
+
if (pkgManager === "deno") return "npm";
|
|
86
|
+
if (pkgManager === "pnpm@6") return "pnpm";
|
|
87
|
+
return pkgManager;
|
|
88
|
+
}
|
|
89
|
+
async #createAceFile(outDir) {
|
|
90
|
+
const aceFileLocation = join(outDir, "ace.js");
|
|
91
|
+
const aceFileContent = dedent(`
|
|
374
92
|
/**
|
|
375
93
|
* This file is auto-generated by the build process.
|
|
376
94
|
* If you had any custom code inside this file, then
|
|
@@ -378,1368 +96,853 @@ var Bundler = class {
|
|
|
378
96
|
*/
|
|
379
97
|
|
|
380
98
|
await import('./bin/console.js')
|
|
381
|
-
`
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
)
|
|
426
|
-
);
|
|
427
|
-
this.ui.logger.logError(instructions.prepare());
|
|
428
|
-
return false;
|
|
429
|
-
}
|
|
430
|
-
const pkgFiles = [
|
|
431
|
-
"package.json",
|
|
432
|
-
...SUPPORTED_PACKAGE_MANAGERS[this.packageManager].packageManagerFiles
|
|
433
|
-
];
|
|
434
|
-
this.ui.logger.info("copying meta files to the output directory");
|
|
435
|
-
await this.#copyMetaFiles(outDir, pkgFiles);
|
|
436
|
-
this.ui.logger.success("build completed");
|
|
437
|
-
this.ui.logger.log("");
|
|
438
|
-
const displayMessage = this.ui.instructions().heading("Run the following commands to start the server in production");
|
|
439
|
-
await this.#hooks.runner("buildFinished").run(this, displayMessage);
|
|
440
|
-
displayMessage.add(this.ui.colors.cyan(`cd ${this.#getRelativeName(outDir)}`)).add(this.ui.colors.cyan(SUPPORTED_PACKAGE_MANAGERS[this.packageManager].installCommand)).add(this.ui.colors.cyan("node bin/server.js")).render();
|
|
441
|
-
return true;
|
|
442
|
-
}
|
|
99
|
+
`);
|
|
100
|
+
await fs.writeFile(aceFileLocation, aceFileContent);
|
|
101
|
+
this.ui.logger.info("created ace file", { suffix: this.#getRelativeName(aceFileLocation) });
|
|
102
|
+
}
|
|
103
|
+
async bundle(stopOnError = true, client) {
|
|
104
|
+
this.packageManager = client ?? await this.#detectPackageManager() ?? "npm";
|
|
105
|
+
const config = parseConfig(this.cwd, this.#ts);
|
|
106
|
+
if (!config) return false;
|
|
107
|
+
this.ui.logger.info("loading hooks...");
|
|
108
|
+
this.#hooks = await loadHooks(this.options.hooks, [
|
|
109
|
+
"init",
|
|
110
|
+
"buildStarting",
|
|
111
|
+
"buildFinished"
|
|
112
|
+
]);
|
|
113
|
+
this.#indexGenerator = new IndexGenerator(this.cwdPath, this.ui.logger);
|
|
114
|
+
await this.#hooks.runner("init").run(this, this.#hooks, this.#indexGenerator);
|
|
115
|
+
this.#hooks.clear("init");
|
|
116
|
+
this.ui.logger.info("generating indexes...");
|
|
117
|
+
await this.#indexGenerator.generate();
|
|
118
|
+
const outDir = config.options.outDir || fileURLToPath(new URL("build/", this.cwd));
|
|
119
|
+
this.ui.logger.info("cleaning up output directory", { suffix: this.#getRelativeName(outDir) });
|
|
120
|
+
await this.#cleanupBuildDirectory(outDir);
|
|
121
|
+
await this.#hooks.runner("buildStarting").run(this);
|
|
122
|
+
this.ui.logger.info("compiling typescript source", { suffix: "tsc" });
|
|
123
|
+
const buildCompleted = await this.#runTsc(outDir);
|
|
124
|
+
await this.#createAceFile(outDir);
|
|
125
|
+
if (!buildCompleted && stopOnError) {
|
|
126
|
+
await this.#cleanupBuildDirectory(outDir);
|
|
127
|
+
const instructions = this.ui.sticker().fullScreen().drawBorder((borderChar, colors) => colors.red(borderChar));
|
|
128
|
+
instructions.add(this.ui.colors.red("Cannot complete the build process as there are TypeScript errors."));
|
|
129
|
+
instructions.add(this.ui.colors.red("Use \"--ignore-ts-errors\" flag to ignore TypeScript errors and continue the build."));
|
|
130
|
+
this.ui.logger.logError(instructions.prepare());
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
const pkgFiles = ["package.json", ...SUPPORTED_PACKAGE_MANAGERS[this.packageManager].packageManagerFiles];
|
|
134
|
+
this.ui.logger.info("copying meta files to the output directory");
|
|
135
|
+
await this.#copyMetaFiles(outDir, pkgFiles);
|
|
136
|
+
this.ui.logger.success("build completed");
|
|
137
|
+
this.ui.logger.log("");
|
|
138
|
+
const displayMessage = this.ui.instructions().heading("Run the following commands to start the server in production");
|
|
139
|
+
await this.#hooks.runner("buildFinished").run(this, displayMessage);
|
|
140
|
+
displayMessage.add(this.ui.colors.cyan(`cd ${this.#getRelativeName(outDir)}`)).add(this.ui.colors.cyan(SUPPORTED_PACKAGE_MANAGERS[this.packageManager].installCommand)).add(this.ui.colors.cyan("node bin/server.js")).render();
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
443
143
|
};
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
import string2 from "@poppinss/utils/string";
|
|
457
|
-
var DEFAULT_INCLUDES = ["**/*"];
|
|
458
|
-
var ALWAYS_EXCLUDE = [".git/**", "coverage/**", ".github/**", ".adonisjs/**"];
|
|
459
|
-
var DEFAULT_EXCLUDES = ["node_modules/**", "bower_components/**", "jspm_packages/**"];
|
|
144
|
+
const DEFAULT_INCLUDES = ["**/*"];
|
|
145
|
+
const ALWAYS_EXCLUDE = [
|
|
146
|
+
".git/**",
|
|
147
|
+
"coverage/**",
|
|
148
|
+
".github/**",
|
|
149
|
+
".adonisjs/**"
|
|
150
|
+
];
|
|
151
|
+
const DEFAULT_EXCLUDES = [
|
|
152
|
+
"node_modules/**",
|
|
153
|
+
"bower_components/**",
|
|
154
|
+
"jspm_packages/**"
|
|
155
|
+
];
|
|
460
156
|
var FileSystem = class {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
unixAbsolutePath: absolutePath
|
|
573
|
-
};
|
|
574
|
-
}
|
|
575
|
-
debug_default('ignored file "%s"', relativePath);
|
|
576
|
-
return null;
|
|
577
|
-
});
|
|
578
|
-
/**
|
|
579
|
-
* Determines if a directory should be watched by the file watcher.
|
|
580
|
-
*
|
|
581
|
-
* This method checks if a directory should be monitored for file changes
|
|
582
|
-
* based on the TypeScript configuration includes/excludes patterns.
|
|
583
|
-
* Results are memoized for performance. Chokidar sends absolute Unix paths.
|
|
584
|
-
*
|
|
585
|
-
* Note: Use shouldWatchFile for files and this method for directories only.
|
|
586
|
-
*
|
|
587
|
-
* @param absolutePath - The absolute Unix path to the directory
|
|
588
|
-
* @returns True if the directory should be watched
|
|
589
|
-
*
|
|
590
|
-
* @example
|
|
591
|
-
* const shouldWatch = fileSystem.shouldWatchDirectory('/project/app/controllers')
|
|
592
|
-
* console.log(shouldWatch) // true
|
|
593
|
-
*/
|
|
594
|
-
shouldWatchDirectory = memoize((absolutePath) => {
|
|
595
|
-
if (absolutePath === this.#cwd) {
|
|
596
|
-
debug_default("watching project root");
|
|
597
|
-
return true;
|
|
598
|
-
}
|
|
599
|
-
const relativePath = relative2(this.#cwd, absolutePath);
|
|
600
|
-
if (this.#isExcluded(relativePath)) {
|
|
601
|
-
debug_default('watching "%s"', absolutePath);
|
|
602
|
-
return false;
|
|
603
|
-
}
|
|
604
|
-
return true;
|
|
605
|
-
});
|
|
606
|
-
/**
|
|
607
|
-
* Create a new FileSystem instance
|
|
608
|
-
*
|
|
609
|
-
* @param cwd - The current working directory URL or string path
|
|
610
|
-
* @param tsConfig - Parsed TypeScript configuration
|
|
611
|
-
* @param rcFile - AdonisJS RC file configuration
|
|
612
|
-
*/
|
|
613
|
-
constructor(cwd, tsConfig, rcFile) {
|
|
614
|
-
this.#cwd = cwd;
|
|
615
|
-
this.#tsConfig = tsConfig;
|
|
616
|
-
const files = tsConfig.fileNames;
|
|
617
|
-
const metaFiles = rcFile.metaFiles ?? [];
|
|
618
|
-
const testSuites = rcFile.suites ?? [];
|
|
619
|
-
const outDir = tsConfig.raw.compilerOptions?.outDir;
|
|
620
|
-
for (const file of files) {
|
|
621
|
-
this.#scannedTypeScriptFiles.add(string2.toUnixSlash(file));
|
|
622
|
-
}
|
|
623
|
-
this.#includes = tsConfig.raw.include || DEFAULT_INCLUDES;
|
|
624
|
-
this.#excludes = ALWAYS_EXCLUDE.concat(
|
|
625
|
-
tsConfig.raw.exclude || (outDir ? DEFAULT_EXCLUDES.concat(outDir) : DEFAULT_EXCLUDES)
|
|
626
|
-
);
|
|
627
|
-
const metaFilesWithReloads = [];
|
|
628
|
-
const metaFilesWithoutReloads = [];
|
|
629
|
-
for (const file of metaFiles) {
|
|
630
|
-
if (file.reloadServer) {
|
|
631
|
-
metaFilesWithReloads.push(file.pattern);
|
|
632
|
-
} else {
|
|
633
|
-
metaFilesWithoutReloads.push(file.pattern);
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
const testFilePatterns = testSuites.flatMap((suite) => suite.files);
|
|
637
|
-
const picomatcchOptions = { cwd: this.#cwd };
|
|
638
|
-
this.#isMetaFileWithReloadsEnabled = picomatch(metaFilesWithReloads, picomatcchOptions);
|
|
639
|
-
this.#isMetaFileWithReloadsDisabled = picomatch(metaFilesWithoutReloads, picomatcchOptions);
|
|
640
|
-
this.#isTestFile = picomatch(testFilePatterns, picomatcchOptions);
|
|
641
|
-
this.#isIncluded = picomatch(this.#includes, picomatcchOptions);
|
|
642
|
-
this.#isExcluded = picomatch(this.#excludes, picomatcchOptions);
|
|
643
|
-
debug_default("initiating file system %O", {
|
|
644
|
-
includes: this.#includes,
|
|
645
|
-
excludes: this.#excludes,
|
|
646
|
-
outDir,
|
|
647
|
-
files,
|
|
648
|
-
metaFiles,
|
|
649
|
-
testSuites
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
/**
|
|
653
|
-
* Determines if a file path represents a script file based on TypeScript configuration.
|
|
654
|
-
*
|
|
655
|
-
* Script files are those that can be processed by the TypeScript compiler:
|
|
656
|
-
* - Files ending with ".ts" or ".tsx" (excluding ".d.ts" declaration files)
|
|
657
|
-
* - Files ending with ".js" when "allowJs" option is enabled in tsconfig
|
|
658
|
-
* - Files ending with ".json" when "resolveJsonModule" option is enabled in tsconfig
|
|
659
|
-
*
|
|
660
|
-
* @param relativePath - The relative file path to check
|
|
661
|
-
* @returns True if the file is a script file
|
|
662
|
-
*/
|
|
663
|
-
#isScriptFile(relativePath) {
|
|
664
|
-
if ((relativePath.endsWith(".ts") || relativePath.endsWith(".tsx")) && !relativePath.endsWith(".d.ts")) {
|
|
665
|
-
return true;
|
|
666
|
-
}
|
|
667
|
-
if (this.#tsConfig.options.allowJs && relativePath.endsWith(".js")) {
|
|
668
|
-
return true;
|
|
669
|
-
}
|
|
670
|
-
if (this.#tsConfig.options.resolveJsonModule && relativePath.endsWith(".json")) {
|
|
671
|
-
return true;
|
|
672
|
-
}
|
|
673
|
-
return false;
|
|
674
|
-
}
|
|
675
|
-
/**
|
|
676
|
-
* Checks if a file path is part of the backend TypeScript project.
|
|
677
|
-
*
|
|
678
|
-
* Uses TypeScript configuration "includes", "excludes", and "files" paths
|
|
679
|
-
* to determine if a file should be considered part of the project compilation.
|
|
680
|
-
*
|
|
681
|
-
* @param relativePath - The relative file path to check
|
|
682
|
-
* @returns True if the file is part of the backend project
|
|
683
|
-
*/
|
|
684
|
-
#isPartOfBackendProject(relativePath) {
|
|
685
|
-
if (this.#isExcluded(relativePath)) {
|
|
686
|
-
debug_default('excluded by tsconfig "%s"', relativePath);
|
|
687
|
-
return false;
|
|
688
|
-
}
|
|
689
|
-
if (this.#isIncluded(relativePath)) {
|
|
690
|
-
debug_default('included by tsconfig "%s"', relativePath);
|
|
691
|
-
return true;
|
|
692
|
-
}
|
|
693
|
-
return false;
|
|
694
|
-
}
|
|
695
|
-
/**
|
|
696
|
-
* Returns true if the file should be watched. Chokidar sends
|
|
697
|
-
* absolute unix paths to the ignored callback.
|
|
698
|
-
*
|
|
699
|
-
* You must use "shouldWatchDirectory" method for directories and call
|
|
700
|
-
* this method for files only.
|
|
701
|
-
*
|
|
702
|
-
* @param absolutePath - The absolute path to the file
|
|
703
|
-
* @returns True if the file should be watched
|
|
704
|
-
*/
|
|
705
|
-
shouldWatchFile(absolutePath) {
|
|
706
|
-
return this.inspect(absolutePath) !== null;
|
|
707
|
-
}
|
|
157
|
+
#cwd;
|
|
158
|
+
#tsConfig;
|
|
159
|
+
#scannedTypeScriptFiles = /* @__PURE__ */ new Set();
|
|
160
|
+
#isIncluded;
|
|
161
|
+
#isExcluded;
|
|
162
|
+
#isMetaFileWithReloadsEnabled;
|
|
163
|
+
#isMetaFileWithReloadsDisabled;
|
|
164
|
+
#isTestFile;
|
|
165
|
+
#includes;
|
|
166
|
+
#excludes;
|
|
167
|
+
get includes() {
|
|
168
|
+
return this.#includes;
|
|
169
|
+
}
|
|
170
|
+
get excludes() {
|
|
171
|
+
return this.#excludes;
|
|
172
|
+
}
|
|
173
|
+
inspect = memoize((absolutePath, relativePath) => {
|
|
174
|
+
relativePath = relativePath ?? relative(this.#cwd, absolutePath);
|
|
175
|
+
if (this.#isScriptFile(relativePath) && (this.#scannedTypeScriptFiles.has(absolutePath) || this.#isPartOfBackendProject(relativePath))) {
|
|
176
|
+
debug_default("backend project file \"%s\"", relativePath);
|
|
177
|
+
const isTestFile = this.#isTestFile(relativePath);
|
|
178
|
+
return {
|
|
179
|
+
fileType: isTestFile ? "test" : "script",
|
|
180
|
+
reloadServer: !isTestFile,
|
|
181
|
+
unixRelativePath: relativePath,
|
|
182
|
+
unixAbsolutePath: absolutePath
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
if (this.#isMetaFileWithReloadsEnabled(relativePath)) {
|
|
186
|
+
debug_default("meta file \"%s\"", relativePath);
|
|
187
|
+
return {
|
|
188
|
+
fileType: "meta",
|
|
189
|
+
reloadServer: true,
|
|
190
|
+
unixRelativePath: relativePath,
|
|
191
|
+
unixAbsolutePath: absolutePath
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
if (this.#isMetaFileWithReloadsDisabled(relativePath)) {
|
|
195
|
+
debug_default("meta file \"%s\"", relativePath);
|
|
196
|
+
return {
|
|
197
|
+
fileType: "meta",
|
|
198
|
+
reloadServer: false,
|
|
199
|
+
unixRelativePath: relativePath,
|
|
200
|
+
unixAbsolutePath: absolutePath
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
debug_default("ignored file \"%s\"", relativePath);
|
|
204
|
+
return null;
|
|
205
|
+
});
|
|
206
|
+
shouldWatchDirectory = memoize((absolutePath) => {
|
|
207
|
+
if (absolutePath === this.#cwd) {
|
|
208
|
+
debug_default("watching project root");
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
const relativePath = relative(this.#cwd, absolutePath);
|
|
212
|
+
if (this.#isExcluded(relativePath)) {
|
|
213
|
+
debug_default("watching \"%s\"", absolutePath);
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
return true;
|
|
217
|
+
});
|
|
218
|
+
constructor(cwd, tsConfig, rcFile) {
|
|
219
|
+
this.#cwd = cwd;
|
|
220
|
+
this.#tsConfig = tsConfig;
|
|
221
|
+
const files = tsConfig.config.files ?? [];
|
|
222
|
+
const metaFiles = rcFile.metaFiles ?? [];
|
|
223
|
+
const testSuites = rcFile.suites ?? [];
|
|
224
|
+
const outDir = tsConfig.config.compilerOptions?.outDir;
|
|
225
|
+
for (const file of files) this.#scannedTypeScriptFiles.add(string.toUnixSlash(file));
|
|
226
|
+
this.#includes = tsConfig.config.include || DEFAULT_INCLUDES;
|
|
227
|
+
this.#excludes = ALWAYS_EXCLUDE.concat(tsConfig.config.exclude || (outDir ? DEFAULT_EXCLUDES.concat(outDir) : DEFAULT_EXCLUDES));
|
|
228
|
+
const metaFilesWithReloads = [];
|
|
229
|
+
const metaFilesWithoutReloads = [];
|
|
230
|
+
for (const file of metaFiles) if (file.reloadServer) metaFilesWithReloads.push(file.pattern);
|
|
231
|
+
else metaFilesWithoutReloads.push(file.pattern);
|
|
232
|
+
const testFilePatterns = testSuites.flatMap((suite) => suite.files);
|
|
233
|
+
const picomatcchOptions = { cwd: this.#cwd };
|
|
234
|
+
this.#isMetaFileWithReloadsEnabled = picomatch(metaFilesWithReloads, picomatcchOptions);
|
|
235
|
+
this.#isMetaFileWithReloadsDisabled = picomatch(metaFilesWithoutReloads, picomatcchOptions);
|
|
236
|
+
this.#isTestFile = picomatch(testFilePatterns, picomatcchOptions);
|
|
237
|
+
this.#isIncluded = picomatch(this.#includes, picomatcchOptions);
|
|
238
|
+
this.#isExcluded = picomatch(this.#excludes, picomatcchOptions);
|
|
239
|
+
debug_default("initiating file system %O", {
|
|
240
|
+
includes: this.#includes,
|
|
241
|
+
excludes: this.#excludes,
|
|
242
|
+
outDir,
|
|
243
|
+
files,
|
|
244
|
+
metaFiles,
|
|
245
|
+
testSuites
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
#isScriptFile(relativePath) {
|
|
249
|
+
if ((relativePath.endsWith(".ts") || relativePath.endsWith(".tsx")) && !relativePath.endsWith(".d.ts")) return true;
|
|
250
|
+
if (this.#tsConfig.config.compilerOptions?.allowJs && relativePath.endsWith(".js")) return true;
|
|
251
|
+
if (this.#tsConfig.config.compilerOptions?.resolveJsonModule && relativePath.endsWith(".json")) return true;
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
#isPartOfBackendProject(relativePath) {
|
|
255
|
+
if (this.#isExcluded(relativePath)) {
|
|
256
|
+
debug_default("excluded by tsconfig \"%s\"", relativePath);
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
if (this.#isIncluded(relativePath)) {
|
|
260
|
+
debug_default("included by tsconfig \"%s\"", relativePath);
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
shouldWatchFile(absolutePath) {
|
|
266
|
+
return this.inspect(absolutePath) !== null;
|
|
267
|
+
}
|
|
708
268
|
};
|
|
709
|
-
|
|
710
|
-
// src/shortcuts_manager.ts
|
|
711
269
|
var ShortcutsManager = class {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
*
|
|
783
|
-
* This method enables raw mode on stdin to capture individual keypresses
|
|
784
|
-
* and sets up the event listener for handling keyboard input. Only works
|
|
785
|
-
* in TTY environments.
|
|
786
|
-
*/
|
|
787
|
-
setup() {
|
|
788
|
-
if (!process.stdin.isTTY) {
|
|
789
|
-
return;
|
|
790
|
-
}
|
|
791
|
-
process.stdin.setRawMode(true);
|
|
792
|
-
this.#keyPressHandler = (data) => this.#handleKeyPress(data.toString());
|
|
793
|
-
process.stdin.on("data", this.#keyPressHandler);
|
|
794
|
-
}
|
|
795
|
-
/**
|
|
796
|
-
* Handle key press events and execute corresponding shortcuts
|
|
797
|
-
*
|
|
798
|
-
* Processes individual key presses and matches them against registered
|
|
799
|
-
* shortcuts. Also handles special key combinations like Ctrl+C and Ctrl+D.
|
|
800
|
-
*
|
|
801
|
-
* @param key - The pressed key as a string
|
|
802
|
-
*/
|
|
803
|
-
#handleKeyPress(key) {
|
|
804
|
-
if (key === "" || key === "") {
|
|
805
|
-
return this.#callbacks.onQuit();
|
|
806
|
-
}
|
|
807
|
-
const shortcut = this.#shortcuts.find((s) => s.key === key);
|
|
808
|
-
if (shortcut) {
|
|
809
|
-
shortcut.handler();
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
/**
|
|
813
|
-
* Handle opening browser with the configured server URL
|
|
814
|
-
*
|
|
815
|
-
* Uses the 'open' package to launch the default browser and navigate
|
|
816
|
-
* to the development server URL.
|
|
817
|
-
*/
|
|
818
|
-
async #handleOpenBrowser() {
|
|
819
|
-
this.#logger.log("");
|
|
820
|
-
this.#logger.info(`Opening ${this.#serverUrl}...`);
|
|
821
|
-
const { default: open } = await import("open");
|
|
822
|
-
open(this.#serverUrl);
|
|
823
|
-
}
|
|
824
|
-
/**
|
|
825
|
-
* Show available keyboard shortcuts in the console
|
|
826
|
-
*
|
|
827
|
-
* Displays a formatted list of all available keyboard shortcuts
|
|
828
|
-
* and their descriptions to help users understand what actions
|
|
829
|
-
* are available.
|
|
830
|
-
*/
|
|
831
|
-
showHelp() {
|
|
832
|
-
this.#logger.log("");
|
|
833
|
-
this.#logger.log("Available shortcuts:");
|
|
834
|
-
this.#shortcuts.forEach(({ key, description }) => this.#logger.log(`\xB7 ${key}: ${description}`));
|
|
835
|
-
}
|
|
836
|
-
/**
|
|
837
|
-
* Cleanup keyboard shortcuts and restore terminal state
|
|
838
|
-
*
|
|
839
|
-
* Disables raw mode on stdin, removes event listeners, and restores
|
|
840
|
-
* the terminal to its normal state. Should be called when shutting down
|
|
841
|
-
* the development server.
|
|
842
|
-
*/
|
|
843
|
-
cleanup() {
|
|
844
|
-
if (!process.stdin.isTTY) {
|
|
845
|
-
return;
|
|
846
|
-
}
|
|
847
|
-
process.stdin.setRawMode(false);
|
|
848
|
-
process.stdin.pause();
|
|
849
|
-
process.stdin.unref();
|
|
850
|
-
process.stdin.removeListener("data", this.#keyPressHandler);
|
|
851
|
-
this.#keyPressHandler = void 0;
|
|
852
|
-
}
|
|
270
|
+
#logger;
|
|
271
|
+
#callbacks;
|
|
272
|
+
#serverUrl;
|
|
273
|
+
#keyPressHandler;
|
|
274
|
+
#shortcuts = [
|
|
275
|
+
{
|
|
276
|
+
key: "r",
|
|
277
|
+
description: "restart server",
|
|
278
|
+
handler: () => {
|
|
279
|
+
this.#logger.log("");
|
|
280
|
+
this.#logger.info("Manual restart triggered...");
|
|
281
|
+
this.#callbacks.onRestart();
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
key: "c",
|
|
286
|
+
description: "clear console",
|
|
287
|
+
handler: () => {
|
|
288
|
+
this.#callbacks.onClear();
|
|
289
|
+
this.#logger.info("Console cleared");
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
key: "o",
|
|
294
|
+
description: "open in browser",
|
|
295
|
+
handler: () => this.#handleOpenBrowser()
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
key: "h",
|
|
299
|
+
description: "show this help",
|
|
300
|
+
handler: () => this.showHelp()
|
|
301
|
+
}
|
|
302
|
+
];
|
|
303
|
+
constructor(options) {
|
|
304
|
+
this.#logger = options.logger;
|
|
305
|
+
this.#callbacks = options.callbacks;
|
|
306
|
+
}
|
|
307
|
+
setServerUrl(url) {
|
|
308
|
+
this.#serverUrl = url;
|
|
309
|
+
}
|
|
310
|
+
setup() {
|
|
311
|
+
if (!process.stdin.isTTY) return;
|
|
312
|
+
process.stdin.setRawMode(true);
|
|
313
|
+
this.#keyPressHandler = (data) => this.#handleKeyPress(data.toString());
|
|
314
|
+
process.stdin.on("data", this.#keyPressHandler);
|
|
315
|
+
}
|
|
316
|
+
#handleKeyPress(key) {
|
|
317
|
+
if (key === "" || key === "") return this.#callbacks.onQuit();
|
|
318
|
+
const shortcut = this.#shortcuts.find((s) => s.key === key);
|
|
319
|
+
if (shortcut) shortcut.handler();
|
|
320
|
+
}
|
|
321
|
+
async #handleOpenBrowser() {
|
|
322
|
+
this.#logger.log("");
|
|
323
|
+
this.#logger.info(`Opening ${this.#serverUrl}...`);
|
|
324
|
+
const { default: open } = await import("open");
|
|
325
|
+
open(this.#serverUrl);
|
|
326
|
+
}
|
|
327
|
+
showHelp() {
|
|
328
|
+
this.#logger.log("");
|
|
329
|
+
this.#logger.log("Available shortcuts:");
|
|
330
|
+
this.#shortcuts.forEach(({ key, description }) => this.#logger.log(`· ${key}: ${description}`));
|
|
331
|
+
}
|
|
332
|
+
cleanup() {
|
|
333
|
+
if (!process.stdin.isTTY) return;
|
|
334
|
+
process.stdin.setRawMode(false);
|
|
335
|
+
process.stdin.pause();
|
|
336
|
+
process.stdin.unref();
|
|
337
|
+
process.stdin.removeListener("data", this.#keyPressHandler);
|
|
338
|
+
this.#keyPressHandler = void 0;
|
|
339
|
+
}
|
|
853
340
|
};
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
this.#onClose?.(result.exitCode);
|
|
1219
|
-
} else {
|
|
1220
|
-
this.ui.logger.info("Underlying HTTP server closed. Still watching for changes");
|
|
1221
|
-
}
|
|
1222
|
-
}).catch((error) => {
|
|
1223
|
-
if (!this.#watcher) {
|
|
1224
|
-
this.#onError?.(error);
|
|
1225
|
-
} else {
|
|
1226
|
-
this.ui.logger.info("Underlying HTTP server died. Still watching for changes");
|
|
1227
|
-
}
|
|
1228
|
-
}).finally(() => {
|
|
1229
|
-
resolve();
|
|
1230
|
-
});
|
|
1231
|
-
});
|
|
1232
|
-
}
|
|
1233
|
-
/**
|
|
1234
|
-
* Add listener to get notified when dev server is closed
|
|
1235
|
-
*
|
|
1236
|
-
* @param callback - Function to call when dev server closes
|
|
1237
|
-
* @returns This DevServer instance for method chaining
|
|
1238
|
-
*/
|
|
1239
|
-
onClose(callback) {
|
|
1240
|
-
this.#onClose = callback;
|
|
1241
|
-
return this;
|
|
1242
|
-
}
|
|
1243
|
-
/**
|
|
1244
|
-
* Add listener to get notified when dev server encounters an error
|
|
1245
|
-
*
|
|
1246
|
-
* @param callback - Function to call when dev server encounters an error
|
|
1247
|
-
* @returns This DevServer instance for method chaining
|
|
1248
|
-
*/
|
|
1249
|
-
onError(callback) {
|
|
1250
|
-
this.#onError = callback;
|
|
1251
|
-
return this;
|
|
1252
|
-
}
|
|
1253
|
-
/**
|
|
1254
|
-
* Close watchers and the running child process
|
|
1255
|
-
*/
|
|
1256
|
-
async close() {
|
|
1257
|
-
this.#cleanupKeyboardShortcuts();
|
|
1258
|
-
await this.#watcher?.close();
|
|
1259
|
-
if (this.#httpServer) {
|
|
1260
|
-
this.#httpServer.removeAllListeners();
|
|
1261
|
-
this.#httpServer.kill("SIGKILL");
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
/**
|
|
1265
|
-
* Start the development server in static or HMR mode
|
|
1266
|
-
*
|
|
1267
|
-
* @param ts - TypeScript module reference
|
|
1268
|
-
*/
|
|
1269
|
-
async start(ts) {
|
|
1270
|
-
const initiated = await this.#init(ts, this.options.hmr ? "hmr" : "static");
|
|
1271
|
-
if (!initiated) {
|
|
1272
|
-
return;
|
|
1273
|
-
}
|
|
1274
|
-
if (this.#mode === "hmr") {
|
|
1275
|
-
this.options.nodeArgs.push("--import=hot-hook/register");
|
|
1276
|
-
this.options.env = {
|
|
1277
|
-
...this.options.env,
|
|
1278
|
-
HOT_HOOK_INCLUDE: this.#fileSystem.includes.join(","),
|
|
1279
|
-
HOT_HOOK_IGNORE: this.#fileSystem.excludes.join(","),
|
|
1280
|
-
HOT_HOOK_RESTART: (this.options.metaFiles ?? []).filter(({ reloadServer }) => !!reloadServer).map(({ pattern }) => pattern).join(",")
|
|
1281
|
-
};
|
|
1282
|
-
}
|
|
1283
|
-
this.ui.logger.info("starting HTTP server...");
|
|
1284
|
-
await this.#startHTTPServer(this.#stickyPort);
|
|
1285
|
-
}
|
|
1286
|
-
/**
|
|
1287
|
-
* Start the development server in watch mode and restart on file changes
|
|
1288
|
-
*
|
|
1289
|
-
* @param ts - TypeScript module reference
|
|
1290
|
-
* @param options - Watch options including polling mode
|
|
1291
|
-
*/
|
|
1292
|
-
async startAndWatch(ts, options) {
|
|
1293
|
-
const initiated = await this.#init(ts, "watch");
|
|
1294
|
-
if (!initiated) {
|
|
1295
|
-
return;
|
|
1296
|
-
}
|
|
1297
|
-
this.ui.logger.info("starting HTTP server...");
|
|
1298
|
-
await this.#startHTTPServer(this.#stickyPort);
|
|
1299
|
-
this.#watcher = watch({
|
|
1300
|
-
usePolling: options?.poll ?? false,
|
|
1301
|
-
cwd: this.cwdPath,
|
|
1302
|
-
ignoreInitial: true,
|
|
1303
|
-
ignored: (file, stats) => {
|
|
1304
|
-
if (!stats) {
|
|
1305
|
-
return false;
|
|
1306
|
-
}
|
|
1307
|
-
if (stats.isFile()) {
|
|
1308
|
-
return !this.#fileSystem.shouldWatchFile(file);
|
|
1309
|
-
}
|
|
1310
|
-
return !this.#fileSystem.shouldWatchDirectory(file);
|
|
1311
|
-
}
|
|
1312
|
-
});
|
|
1313
|
-
this.#watcher.on("ready", () => {
|
|
1314
|
-
this.ui.logger.info("watching file system for changes...");
|
|
1315
|
-
});
|
|
1316
|
-
this.#watcher.on("error", (error) => {
|
|
1317
|
-
this.ui.logger.warning("file system watcher failure");
|
|
1318
|
-
this.ui.logger.fatal(error);
|
|
1319
|
-
this.#onError?.(error);
|
|
1320
|
-
this.#watcher?.close();
|
|
1321
|
-
});
|
|
1322
|
-
this.#watcher.on("add", (filePath) => {
|
|
1323
|
-
const relativePath = string3.toUnixSlash(filePath);
|
|
1324
|
-
const absolutePath = join2(this.cwdPath, relativePath);
|
|
1325
|
-
this.#hooks.runner("fileAdded").run(relativePath, absolutePath, this);
|
|
1326
|
-
});
|
|
1327
|
-
this.#watcher.on("change", (filePath) => {
|
|
1328
|
-
const relativePath = string3.toUnixSlash(filePath);
|
|
1329
|
-
const absolutePath = join2(this.cwdPath, relativePath);
|
|
1330
|
-
this.#hooks.runner("fileChanged").run(relativePath, absolutePath, _DevServer.#WATCHER_INFO, this);
|
|
1331
|
-
});
|
|
1332
|
-
this.#watcher.on("unlink", (filePath) => {
|
|
1333
|
-
const relativePath = string3.toUnixSlash(filePath);
|
|
1334
|
-
const absolutePath = join2(this.cwdPath, relativePath);
|
|
1335
|
-
this.#hooks.runner("fileRemoved").run(relativePath, absolutePath, this);
|
|
1336
|
-
});
|
|
1337
|
-
}
|
|
341
|
+
var DevServer = class DevServer {
|
|
342
|
+
static #HOT_HOOK_FULL_RELOAD_INFO = {
|
|
343
|
+
source: "hot-hook",
|
|
344
|
+
fullReload: true,
|
|
345
|
+
hotReloaded: false
|
|
346
|
+
};
|
|
347
|
+
static #HOT_HOOK_INVALIDATED_INFO = {
|
|
348
|
+
source: "hot-hook",
|
|
349
|
+
fullReload: false,
|
|
350
|
+
hotReloaded: true
|
|
351
|
+
};
|
|
352
|
+
static #WATCHER_INFO = {
|
|
353
|
+
source: "watcher",
|
|
354
|
+
fullReload: true,
|
|
355
|
+
hotReloaded: false
|
|
356
|
+
};
|
|
357
|
+
#onError;
|
|
358
|
+
#onClose;
|
|
359
|
+
#stickyPort;
|
|
360
|
+
#stickyHmrPort;
|
|
361
|
+
#mode = "static";
|
|
362
|
+
#watcher;
|
|
363
|
+
#httpServer;
|
|
364
|
+
#isHttpServerAlive = false;
|
|
365
|
+
#shortcutsManager;
|
|
366
|
+
#fileSystem;
|
|
367
|
+
#indexGenerator;
|
|
368
|
+
#routesScanner;
|
|
369
|
+
#hooks;
|
|
370
|
+
ui = cliui();
|
|
371
|
+
#restartHTTPServer = throttle(async () => {
|
|
372
|
+
if (this.#httpServer) {
|
|
373
|
+
this.#httpServer.removeAllListeners();
|
|
374
|
+
this.#httpServer.kill("SIGKILL");
|
|
375
|
+
}
|
|
376
|
+
await this.#startHTTPServer(this.#stickyPort, this.#stickyHmrPort);
|
|
377
|
+
}, "restartHTTPServer");
|
|
378
|
+
#setupKeyboardShortcuts() {
|
|
379
|
+
this.#shortcutsManager = new ShortcutsManager({
|
|
380
|
+
logger: this.ui.logger,
|
|
381
|
+
callbacks: {
|
|
382
|
+
onRestart: () => this.#restartHTTPServer(),
|
|
383
|
+
onClear: () => this.#clearScreen(),
|
|
384
|
+
onQuit: () => this.close()
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
this.#shortcutsManager.setup();
|
|
388
|
+
}
|
|
389
|
+
#cleanupKeyboardShortcuts() {
|
|
390
|
+
this.#shortcutsManager?.cleanup();
|
|
391
|
+
}
|
|
392
|
+
get mode() {
|
|
393
|
+
return this.#mode;
|
|
394
|
+
}
|
|
395
|
+
scriptFile = "bin/server.ts";
|
|
396
|
+
cwd;
|
|
397
|
+
cwdPath;
|
|
398
|
+
options;
|
|
399
|
+
constructor(cwd, options) {
|
|
400
|
+
this.cwd = cwd;
|
|
401
|
+
this.options = options;
|
|
402
|
+
this.cwdPath = string.toUnixSlash(fileURLToPath(this.cwd));
|
|
403
|
+
}
|
|
404
|
+
#isAdonisJSReadyMessage(message) {
|
|
405
|
+
return message !== null && typeof message === "object" && "isAdonisJS" in message && "environment" in message && message.environment === "web";
|
|
406
|
+
}
|
|
407
|
+
#isAdonisJSRoutesMessage(message) {
|
|
408
|
+
return message !== null && typeof message === "object" && "routesFileLocation" in message;
|
|
409
|
+
}
|
|
410
|
+
async #postServerReady(message) {
|
|
411
|
+
const host = message.host === "0.0.0.0" ? "127.0.0.1" : message.host;
|
|
412
|
+
const info = {
|
|
413
|
+
host,
|
|
414
|
+
port: message.port
|
|
415
|
+
};
|
|
416
|
+
const serverUrl = `http://${host}:${message.port}`;
|
|
417
|
+
this.#shortcutsManager?.setServerUrl(serverUrl);
|
|
418
|
+
const displayMessage = this.ui.sticker().add(`Server address: ${this.ui.colors.cyan(serverUrl)}`).add(`Mode: ${this.ui.colors.cyan(this.mode)}`);
|
|
419
|
+
if (message.duration) displayMessage.add(`Ready in: ${this.ui.colors.cyan(prettyHrtime(message.duration))}`);
|
|
420
|
+
displayMessage.add(`Press ${this.ui.colors.dim("h")} to show help`);
|
|
421
|
+
try {
|
|
422
|
+
await this.#hooks.runner("devServerStarted").run(this, info, displayMessage);
|
|
423
|
+
} catch (error) {
|
|
424
|
+
this.ui.logger.error("One of the \"devServerStarted\" hooks failed");
|
|
425
|
+
this.ui.logger.fatal(error);
|
|
426
|
+
}
|
|
427
|
+
displayMessage.render();
|
|
428
|
+
}
|
|
429
|
+
#isHotHookMessage(message) {
|
|
430
|
+
return message !== null && typeof message === "object" && "type" in message && typeof message.type === "string" && message.type.startsWith("hot-hook:");
|
|
431
|
+
}
|
|
432
|
+
#clearScreen() {
|
|
433
|
+
if (this.options.clearScreen) process.stdout.write("\x1Bc");
|
|
434
|
+
}
|
|
435
|
+
#createWatcher(options) {
|
|
436
|
+
const watcher = watch({
|
|
437
|
+
usePolling: options?.poll ?? false,
|
|
438
|
+
cwd: this.cwdPath,
|
|
439
|
+
ignoreInitial: true,
|
|
440
|
+
ignored: (file, stats) => {
|
|
441
|
+
if (!stats) return false;
|
|
442
|
+
if (file.includes("inertia") && !file.includes("node_modules")) return false;
|
|
443
|
+
if (stats.isFile()) return !this.#fileSystem.shouldWatchFile(file);
|
|
444
|
+
return !this.#fileSystem.shouldWatchDirectory(file);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
watcher.on("error", (error) => {
|
|
448
|
+
this.ui.logger.warning("file system watcher failure");
|
|
449
|
+
this.ui.logger.fatal(error);
|
|
450
|
+
this.#onError?.(error);
|
|
451
|
+
this.#watcher?.close();
|
|
452
|
+
});
|
|
453
|
+
watcher.on("ready", () => {
|
|
454
|
+
this.ui.logger.info("watching file system for changes...");
|
|
455
|
+
});
|
|
456
|
+
return watcher;
|
|
457
|
+
}
|
|
458
|
+
#handleHmrWatcherEvent(options) {
|
|
459
|
+
const relativePath = string.toUnixSlash(options.filePath);
|
|
460
|
+
const absolutePath = join(this.cwdPath, relativePath);
|
|
461
|
+
if (this.#isHttpServerAlive === false) {
|
|
462
|
+
this.#clearScreen();
|
|
463
|
+
this.ui.logger.log(`${this.ui.colors.green(options.displayLabel)} ${relativePath}`);
|
|
464
|
+
this.#restartHTTPServer();
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
if (options.action === "add") this.#hooks.runner("fileAdded").run(relativePath, absolutePath, this);
|
|
468
|
+
else if (options.action === "unlink") this.#hooks.runner("fileRemoved").run(relativePath, absolutePath, this);
|
|
469
|
+
this.#httpServer?.send({
|
|
470
|
+
type: "hot-hook:file-changed",
|
|
471
|
+
path: absolutePath,
|
|
472
|
+
action: options.action
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
#handleFileChange(relativePath, absolutePath, action, info) {
|
|
476
|
+
if ((action === "add" || action === "delete") && this.mode === "hmr") {
|
|
477
|
+
debug_default("ignoring add and delete actions in HMR mode %s", relativePath);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (info && info.source === "hot-hook" && info.hotReloaded) {
|
|
481
|
+
debug_default("hot reloading %s, info %O", relativePath, info);
|
|
482
|
+
this.ui.logger.log(`${this.ui.colors.green("invalidated")} ${relativePath}`);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
if (info && !info.fullReload) {
|
|
486
|
+
debug_default("ignoring full reload", relativePath, info);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
const file = this.#fileSystem.inspect(absolutePath, relativePath);
|
|
490
|
+
if (!file) return;
|
|
491
|
+
if (file.reloadServer) {
|
|
492
|
+
this.#clearScreen();
|
|
493
|
+
this.ui.logger.log(`${this.ui.colors.green(action)} ${relativePath}`);
|
|
494
|
+
this.#restartHTTPServer();
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
this.ui.logger.log(`${this.ui.colors.green(action)} ${relativePath}`);
|
|
498
|
+
}
|
|
499
|
+
#regenerateIndex(filePath, action) {
|
|
500
|
+
if (action === "add") return this.#indexGenerator.addFile(filePath);
|
|
501
|
+
return this.#indexGenerator.removeFile(filePath);
|
|
502
|
+
}
|
|
503
|
+
async #reScanRoutes(filePath) {
|
|
504
|
+
if (!this.#routesScanner) return;
|
|
505
|
+
try {
|
|
506
|
+
if (await this.#routesScanner.invalidate(filePath)) await this.#hooks.runner("routesScanned").run(this, this.#routesScanner);
|
|
507
|
+
} catch (error) {
|
|
508
|
+
this.ui.logger.error("Unable to rescan routes because of the following error");
|
|
509
|
+
this.ui.logger.fatal(error);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
#processRoutes = throttle(async (routesFileLocation) => {
|
|
513
|
+
try {
|
|
514
|
+
const scanRoutes = this.#hooks.has("routesScanning") || this.#hooks.has("routesScanned");
|
|
515
|
+
const shareRoutes = this.#hooks.has("routesCommitted");
|
|
516
|
+
if (!scanRoutes && !shareRoutes) {
|
|
517
|
+
unlink(routesFileLocation).catch(() => {});
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
const routesJSON = await readFile(routesFileLocation, "utf-8");
|
|
521
|
+
const routesList = JSON.parse(routesJSON);
|
|
522
|
+
unlink(routesFileLocation).catch(() => {});
|
|
523
|
+
if (shareRoutes) await this.#hooks.runner("routesCommitted").run(this, routesList);
|
|
524
|
+
if (scanRoutes) {
|
|
525
|
+
this.#routesScanner = new RoutesScanner(this.cwdPath, []);
|
|
526
|
+
await this.#hooks.runner("routesScanning").run(this, this.#routesScanner);
|
|
527
|
+
for (const domain of Object.keys(routesList)) await this.#routesScanner.scan(routesList[domain]);
|
|
528
|
+
await this.#hooks.runner("routesScanned").run(this, this.#routesScanner);
|
|
529
|
+
}
|
|
530
|
+
} catch (error) {
|
|
531
|
+
this.ui.logger.error("Unable to process and scan routes because of the following error");
|
|
532
|
+
this.ui.logger.fatal(error);
|
|
533
|
+
}
|
|
534
|
+
}, "processRoutes");
|
|
535
|
+
#registerServerRestartHooks() {
|
|
536
|
+
this.#hooks.add("fileAdded", (relativePath, absolutePath) => {
|
|
537
|
+
this.#regenerateIndex(absolutePath, "add");
|
|
538
|
+
this.#handleFileChange(relativePath, absolutePath, "add");
|
|
539
|
+
});
|
|
540
|
+
this.#hooks.add("fileChanged", (relativePath, absolutePath, info) => {
|
|
541
|
+
if (info.hotReloaded || !info.hotReloaded && !info.fullReload) this.#reScanRoutes(absolutePath);
|
|
542
|
+
this.#handleFileChange(relativePath, absolutePath, "update", info);
|
|
543
|
+
});
|
|
544
|
+
this.#hooks.add("fileRemoved", (relativePath, absolutePath) => {
|
|
545
|
+
this.#regenerateIndex(absolutePath, "delete");
|
|
546
|
+
this.#handleFileChange(relativePath, absolutePath, "delete");
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
async #init(mode) {
|
|
550
|
+
const tsConfig = readTsConfig(this.cwdPath);
|
|
551
|
+
if (!tsConfig) {
|
|
552
|
+
this.#onError?.(new RuntimeException("Unable to parse tsconfig file"));
|
|
553
|
+
return false;
|
|
554
|
+
}
|
|
555
|
+
this.#mode = mode;
|
|
556
|
+
this.#clearScreen();
|
|
557
|
+
this.ui.logger.info(`starting server in ${this.#mode} mode...`);
|
|
558
|
+
this.#indexGenerator = new IndexGenerator(this.cwdPath, this.ui.logger);
|
|
559
|
+
this.#stickyPort = String(await getPort(this.cwd));
|
|
560
|
+
this.#stickyHmrPort = String(await getRandomPort({ port: 24678 }));
|
|
561
|
+
this.#fileSystem = new FileSystem(this.cwdPath, tsConfig, this.options);
|
|
562
|
+
this.ui.logger.info("loading hooks...");
|
|
563
|
+
this.#hooks = await loadHooks(this.options.hooks, [
|
|
564
|
+
"init",
|
|
565
|
+
"routesCommitted",
|
|
566
|
+
"routesScanning",
|
|
567
|
+
"routesScanned",
|
|
568
|
+
"devServerStarting",
|
|
569
|
+
"devServerStarted",
|
|
570
|
+
"fileAdded",
|
|
571
|
+
"fileChanged",
|
|
572
|
+
"fileRemoved"
|
|
573
|
+
]);
|
|
574
|
+
this.#registerServerRestartHooks();
|
|
575
|
+
this.#setupKeyboardShortcuts();
|
|
576
|
+
await this.#hooks.runner("init").run(this, this.#hooks, this.#indexGenerator);
|
|
577
|
+
this.#hooks.clear("init");
|
|
578
|
+
this.ui.logger.info("generating indexes...");
|
|
579
|
+
await this.#indexGenerator.generate();
|
|
580
|
+
return true;
|
|
581
|
+
}
|
|
582
|
+
async #startHTTPServer(port, hmrPort) {
|
|
583
|
+
await this.#hooks.runner("devServerStarting").run(this);
|
|
584
|
+
debug_default("starting http server using \"%s\" file, options %O", this.scriptFile, this.options);
|
|
585
|
+
return new Promise((resolve) => {
|
|
586
|
+
this.#httpServer = runNode(this.cwd, {
|
|
587
|
+
script: this.scriptFile,
|
|
588
|
+
env: {
|
|
589
|
+
PORT: port,
|
|
590
|
+
VITE_HMR_PORT: hmrPort,
|
|
591
|
+
DEV_MODE: "true",
|
|
592
|
+
...this.options.env
|
|
593
|
+
},
|
|
594
|
+
nodeArgs: this.options.nodeArgs,
|
|
595
|
+
reject: true,
|
|
596
|
+
scriptArgs: this.options.scriptArgs
|
|
597
|
+
});
|
|
598
|
+
this.#isHttpServerAlive = true;
|
|
599
|
+
this.#httpServer.on("message", async (message) => {
|
|
600
|
+
if (this.#isAdonisJSReadyMessage(message)) {
|
|
601
|
+
debug_default("received http server ready message %O", message);
|
|
602
|
+
await this.#postServerReady(message);
|
|
603
|
+
resolve();
|
|
604
|
+
} else if (this.#isAdonisJSRoutesMessage(message)) {
|
|
605
|
+
debug_default("received routes location from the server %O", message);
|
|
606
|
+
await this.#processRoutes(message.routesFileLocation);
|
|
607
|
+
} else if (this.#mode === "hmr" && this.#isHotHookMessage(message)) {
|
|
608
|
+
debug_default("received hot-hook message %O", message);
|
|
609
|
+
if (message.type === "hot-hook:full-reload") {
|
|
610
|
+
const absolutePath = message.path ? string.toUnixSlash(message.path) : "";
|
|
611
|
+
const relativePath = relative(this.cwdPath, absolutePath);
|
|
612
|
+
this.#hooks.runner("fileChanged").run(relativePath, absolutePath, DevServer.#HOT_HOOK_FULL_RELOAD_INFO, this);
|
|
613
|
+
} else if (message.type === "hot-hook:invalidated") {
|
|
614
|
+
const absolutePath = message.paths[0] ? string.toUnixSlash(message.paths[0]) : "";
|
|
615
|
+
const relativePath = relative(this.cwdPath, absolutePath);
|
|
616
|
+
this.#hooks.runner("fileChanged").run(relativePath, absolutePath, DevServer.#HOT_HOOK_INVALIDATED_INFO, this);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
this.#httpServer.then((result) => {
|
|
621
|
+
this.#isHttpServerAlive = false;
|
|
622
|
+
if (!this.#watcher) this.#onClose?.(result.exitCode);
|
|
623
|
+
else this.ui.logger.info("Underlying HTTP server closed. Still watching for changes");
|
|
624
|
+
}).catch((error) => {
|
|
625
|
+
this.#isHttpServerAlive = false;
|
|
626
|
+
if (!this.#watcher) this.#onError?.(error);
|
|
627
|
+
else this.ui.logger.info("Underlying HTTP server died. Still watching for changes");
|
|
628
|
+
}).finally(() => {
|
|
629
|
+
resolve();
|
|
630
|
+
});
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
onClose(callback) {
|
|
634
|
+
this.#onClose = callback;
|
|
635
|
+
return this;
|
|
636
|
+
}
|
|
637
|
+
onError(callback) {
|
|
638
|
+
this.#onError = callback;
|
|
639
|
+
return this;
|
|
640
|
+
}
|
|
641
|
+
async close() {
|
|
642
|
+
this.#cleanupKeyboardShortcuts();
|
|
643
|
+
await this.#watcher?.close();
|
|
644
|
+
if (this.#httpServer) {
|
|
645
|
+
this.#httpServer.removeAllListeners();
|
|
646
|
+
this.#httpServer.kill("SIGKILL");
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
async start() {
|
|
650
|
+
if (!await this.#init(this.options.hmr ? "hmr" : "static")) return;
|
|
651
|
+
if (this.#mode === "hmr") {
|
|
652
|
+
this.options.nodeArgs.push("--import=hot-hook/register");
|
|
653
|
+
this.options.env = {
|
|
654
|
+
...this.options.env,
|
|
655
|
+
HOT_HOOK_WATCH: "false"
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
this.ui.logger.info("starting HTTP server...");
|
|
659
|
+
await this.#startHTTPServer(this.#stickyPort, this.#stickyHmrPort);
|
|
660
|
+
if (this.#mode !== "hmr") return;
|
|
661
|
+
this.#watcher = this.#createWatcher();
|
|
662
|
+
this.#watcher.on("add", (filePath) => {
|
|
663
|
+
this.#handleHmrWatcherEvent({
|
|
664
|
+
filePath,
|
|
665
|
+
action: "add",
|
|
666
|
+
displayLabel: "add"
|
|
667
|
+
});
|
|
668
|
+
});
|
|
669
|
+
this.#watcher.on("change", (filePath) => {
|
|
670
|
+
this.#handleHmrWatcherEvent({
|
|
671
|
+
filePath,
|
|
672
|
+
action: "change",
|
|
673
|
+
displayLabel: "update"
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
this.#watcher.on("unlink", (filePath) => {
|
|
677
|
+
this.#handleHmrWatcherEvent({
|
|
678
|
+
filePath,
|
|
679
|
+
action: "unlink",
|
|
680
|
+
displayLabel: "delete"
|
|
681
|
+
});
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
async startAndWatch(options) {
|
|
685
|
+
if (!await this.#init("watch")) return;
|
|
686
|
+
this.ui.logger.info("starting HTTP server...");
|
|
687
|
+
await this.#startHTTPServer(this.#stickyPort, this.#stickyHmrPort);
|
|
688
|
+
this.#watcher = this.#createWatcher({ poll: options?.poll });
|
|
689
|
+
this.#watcher.on("add", (filePath) => {
|
|
690
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
691
|
+
const absolutePath = join(this.cwdPath, relativePath);
|
|
692
|
+
this.#hooks.runner("fileAdded").run(relativePath, absolutePath, this);
|
|
693
|
+
});
|
|
694
|
+
this.#watcher.on("change", (filePath) => {
|
|
695
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
696
|
+
const absolutePath = join(this.cwdPath, relativePath);
|
|
697
|
+
this.#hooks.runner("fileChanged").run(relativePath, absolutePath, DevServer.#WATCHER_INFO, this);
|
|
698
|
+
});
|
|
699
|
+
this.#watcher.on("unlink", (filePath) => {
|
|
700
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
701
|
+
const absolutePath = join(this.cwdPath, relativePath);
|
|
702
|
+
this.#hooks.runner("fileRemoved").run(relativePath, absolutePath, this);
|
|
703
|
+
});
|
|
704
|
+
}
|
|
1338
705
|
};
|
|
1339
|
-
|
|
1340
|
-
// src/test_runner.ts
|
|
1341
|
-
import { join as join3 } from "path/posix";
|
|
1342
|
-
import { cliui as cliui3 } from "@poppinss/cliui";
|
|
1343
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1344
|
-
import string4 from "@poppinss/utils/string";
|
|
1345
|
-
import { RuntimeException as RuntimeException2 } from "@poppinss/utils/exception";
|
|
1346
706
|
var TestRunner = class {
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
this.#regenerateIndex(absolutePath, "delete");
|
|
1588
|
-
this.#handleFileChange(relativePath, absolutePath, "delete");
|
|
1589
|
-
});
|
|
1590
|
-
}
|
|
1591
|
-
/**
|
|
1592
|
-
* Add listener to get notified when test runner is closed
|
|
1593
|
-
*
|
|
1594
|
-
* @param callback - Function to call when test runner closes
|
|
1595
|
-
* @returns This TestRunner instance for method chaining
|
|
1596
|
-
*/
|
|
1597
|
-
onClose(callback) {
|
|
1598
|
-
this.#onClose = callback;
|
|
1599
|
-
return this;
|
|
1600
|
-
}
|
|
1601
|
-
/**
|
|
1602
|
-
* Add listener to get notified when test runner encounters an error
|
|
1603
|
-
*
|
|
1604
|
-
* @param callback - Function to call when test runner encounters an error
|
|
1605
|
-
* @returns This TestRunner instance for method chaining
|
|
1606
|
-
*/
|
|
1607
|
-
onError(callback) {
|
|
1608
|
-
this.#onError = callback;
|
|
1609
|
-
return this;
|
|
1610
|
-
}
|
|
1611
|
-
/**
|
|
1612
|
-
* Close watchers and running child processes
|
|
1613
|
-
*
|
|
1614
|
-
* Cleans up file system watchers and terminates any running test
|
|
1615
|
-
* processes to ensure graceful shutdown.
|
|
1616
|
-
*/
|
|
1617
|
-
async close() {
|
|
1618
|
-
await this.#watcher?.close();
|
|
1619
|
-
if (this.#testsProcess) {
|
|
1620
|
-
this.#testsProcess.removeAllListeners();
|
|
1621
|
-
this.#testsProcess.kill("SIGKILL");
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
/**
|
|
1625
|
-
* Runs tests once without watching for file changes
|
|
1626
|
-
*
|
|
1627
|
-
* Executes the test suite a single time and exits. This is the
|
|
1628
|
-
* equivalent of running tests in CI/CD environments.
|
|
1629
|
-
*/
|
|
1630
|
-
async run() {
|
|
1631
|
-
this.#stickyPort = String(await getPort(this.cwd));
|
|
1632
|
-
this.#indexGenerator = new IndexGenerator(this.cwdPath, this.ui.logger);
|
|
1633
|
-
this.#clearScreen();
|
|
1634
|
-
this.ui.logger.info("loading hooks...");
|
|
1635
|
-
this.#hooks = await loadHooks(this.options.hooks, ["init", "testsStarting", "testsFinished"]);
|
|
1636
|
-
await this.#hooks.runner("init").run(this, this.#indexGenerator);
|
|
1637
|
-
this.#hooks.clear("init");
|
|
1638
|
-
this.ui.logger.info("generating indexes...");
|
|
1639
|
-
await this.#indexGenerator.generate();
|
|
1640
|
-
this.ui.logger.info("booting application to run tests...");
|
|
1641
|
-
await this.#runTests(this.#stickyPort);
|
|
1642
|
-
}
|
|
1643
|
-
/**
|
|
1644
|
-
* Run tests in watch mode and re-run them when files change
|
|
1645
|
-
*
|
|
1646
|
-
* Starts the test runner in watch mode, monitoring the file system
|
|
1647
|
-
* for changes and automatically re-running tests when relevant files
|
|
1648
|
-
* are modified. Uses intelligent filtering to run only affected tests
|
|
1649
|
-
* when possible.
|
|
1650
|
-
*
|
|
1651
|
-
* @param ts - TypeScript module reference for parsing configuration
|
|
1652
|
-
* @param options - Watch options including polling mode for file system monitoring
|
|
1653
|
-
*/
|
|
1654
|
-
async runAndWatch(ts, options) {
|
|
1655
|
-
const tsConfig = parseConfig(this.cwd, ts);
|
|
1656
|
-
if (!tsConfig) {
|
|
1657
|
-
this.#onError?.(new RuntimeException2("Unable to parse tsconfig file"));
|
|
1658
|
-
return;
|
|
1659
|
-
}
|
|
1660
|
-
this.#stickyPort = String(await getPort(this.cwd));
|
|
1661
|
-
this.#indexGenerator = new IndexGenerator(this.cwdPath, this.ui.logger);
|
|
1662
|
-
this.#fileSystem = new FileSystem(this.cwdPath, tsConfig, {
|
|
1663
|
-
...this.options,
|
|
1664
|
-
suites: this.options.suites?.filter((suite) => {
|
|
1665
|
-
if (this.options.filters.suites) {
|
|
1666
|
-
return this.options.filters.suites.includes(suite.name);
|
|
1667
|
-
}
|
|
1668
|
-
return true;
|
|
1669
|
-
})
|
|
1670
|
-
});
|
|
1671
|
-
this.#clearScreen();
|
|
1672
|
-
this.ui.logger.info("loading hooks...");
|
|
1673
|
-
this.#hooks = await loadHooks(this.options.hooks, [
|
|
1674
|
-
"init",
|
|
1675
|
-
"testsStarting",
|
|
1676
|
-
"testsFinished",
|
|
1677
|
-
"fileAdded",
|
|
1678
|
-
"fileChanged",
|
|
1679
|
-
"fileRemoved"
|
|
1680
|
-
]);
|
|
1681
|
-
this.#registerServerRestartHooks();
|
|
1682
|
-
await this.#hooks.runner("init").run(this, this.#indexGenerator);
|
|
1683
|
-
this.#hooks.clear("init");
|
|
1684
|
-
this.ui.logger.info("generating indexes...");
|
|
1685
|
-
await this.#indexGenerator.generate();
|
|
1686
|
-
this.ui.logger.info("booting application to run tests...");
|
|
1687
|
-
await this.#runTests(this.#stickyPort);
|
|
1688
|
-
this.#watcher = watch({
|
|
1689
|
-
usePolling: options?.poll ?? false,
|
|
1690
|
-
cwd: this.cwdPath,
|
|
1691
|
-
ignoreInitial: true,
|
|
1692
|
-
ignored: (file, stats) => {
|
|
1693
|
-
if (!stats) {
|
|
1694
|
-
return false;
|
|
1695
|
-
}
|
|
1696
|
-
if (stats.isFile()) {
|
|
1697
|
-
return !this.#fileSystem.shouldWatchFile(file);
|
|
1698
|
-
}
|
|
1699
|
-
return !this.#fileSystem.shouldWatchDirectory(file);
|
|
1700
|
-
}
|
|
1701
|
-
});
|
|
1702
|
-
this.#watcher.on("ready", () => {
|
|
1703
|
-
this.ui.logger.info("watching file system for changes...");
|
|
1704
|
-
});
|
|
1705
|
-
this.#watcher.on("error", (error) => {
|
|
1706
|
-
this.ui.logger.warning("file system watcher failure");
|
|
1707
|
-
this.ui.logger.fatal(error);
|
|
1708
|
-
this.#onError?.(error);
|
|
1709
|
-
this.#watcher?.close();
|
|
1710
|
-
});
|
|
1711
|
-
this.#watcher.on("add", (filePath) => {
|
|
1712
|
-
const relativePath = string4.toUnixSlash(filePath);
|
|
1713
|
-
const absolutePath = join3(this.cwdPath, filePath);
|
|
1714
|
-
this.#hooks.runner("fileAdded").run(relativePath, absolutePath, this);
|
|
1715
|
-
});
|
|
1716
|
-
this.#watcher.on("change", (filePath) => {
|
|
1717
|
-
const relativePath = string4.toUnixSlash(filePath);
|
|
1718
|
-
const absolutePath = join3(this.cwdPath, filePath);
|
|
1719
|
-
this.#hooks.runner("fileChanged").run(
|
|
1720
|
-
relativePath,
|
|
1721
|
-
absolutePath,
|
|
1722
|
-
{
|
|
1723
|
-
source: "watcher",
|
|
1724
|
-
fullReload: true,
|
|
1725
|
-
hotReloaded: false
|
|
1726
|
-
},
|
|
1727
|
-
this
|
|
1728
|
-
);
|
|
1729
|
-
});
|
|
1730
|
-
this.#watcher.on("unlink", (filePath) => {
|
|
1731
|
-
const relativePath = string4.toUnixSlash(filePath);
|
|
1732
|
-
const absolutePath = join3(this.cwdPath, filePath);
|
|
1733
|
-
this.#hooks.runner("fileRemoved").run(relativePath, absolutePath, this);
|
|
1734
|
-
});
|
|
1735
|
-
}
|
|
1736
|
-
};
|
|
1737
|
-
export {
|
|
1738
|
-
Bundler,
|
|
1739
|
-
DevServer,
|
|
1740
|
-
FileBuffer,
|
|
1741
|
-
SUPPORTED_PACKAGE_MANAGERS,
|
|
1742
|
-
TestRunner,
|
|
1743
|
-
VirtualFileSystem,
|
|
1744
|
-
hooks
|
|
707
|
+
#onError;
|
|
708
|
+
#onClose;
|
|
709
|
+
#stickyPort;
|
|
710
|
+
#stickyHmrPort;
|
|
711
|
+
#watcher;
|
|
712
|
+
#testsProcess;
|
|
713
|
+
#fileSystem;
|
|
714
|
+
#hooks;
|
|
715
|
+
#indexGenerator;
|
|
716
|
+
ui = cliui();
|
|
717
|
+
#reRunTests = throttle(async (filters) => {
|
|
718
|
+
if (this.#testsProcess) {
|
|
719
|
+
this.#testsProcess.removeAllListeners();
|
|
720
|
+
this.#testsProcess.kill("SIGKILL");
|
|
721
|
+
}
|
|
722
|
+
await this.#runTests(this.#stickyPort, this.#stickyHmrPort, filters);
|
|
723
|
+
}, "reRunTests");
|
|
724
|
+
scriptFile = "bin/test.ts";
|
|
725
|
+
cwd;
|
|
726
|
+
cwdPath;
|
|
727
|
+
options;
|
|
728
|
+
constructor(cwd, options) {
|
|
729
|
+
this.cwd = cwd;
|
|
730
|
+
this.options = options;
|
|
731
|
+
this.cwdPath = string.toUnixSlash(fileURLToPath(this.cwd));
|
|
732
|
+
}
|
|
733
|
+
#convertOptionsToArgs() {
|
|
734
|
+
const args = [];
|
|
735
|
+
if (this.options.reporters) {
|
|
736
|
+
args.push("--reporters");
|
|
737
|
+
args.push(this.options.reporters.join(","));
|
|
738
|
+
}
|
|
739
|
+
if (this.options.timeout !== void 0) {
|
|
740
|
+
args.push("--timeout");
|
|
741
|
+
args.push(String(this.options.timeout));
|
|
742
|
+
}
|
|
743
|
+
if (this.options.failed) args.push("--failed");
|
|
744
|
+
if (this.options.retries !== void 0) {
|
|
745
|
+
args.push("--retries");
|
|
746
|
+
args.push(String(this.options.retries));
|
|
747
|
+
}
|
|
748
|
+
return args;
|
|
749
|
+
}
|
|
750
|
+
#convertFiltersToArgs(filters) {
|
|
751
|
+
const args = [];
|
|
752
|
+
if (filters.suites) args.push(...filters.suites);
|
|
753
|
+
if (filters.files) {
|
|
754
|
+
args.push("--files");
|
|
755
|
+
args.push(filters.files.join(","));
|
|
756
|
+
}
|
|
757
|
+
if (filters.groups) {
|
|
758
|
+
args.push("--groups");
|
|
759
|
+
args.push(filters.groups.join(","));
|
|
760
|
+
}
|
|
761
|
+
if (filters.tags) {
|
|
762
|
+
args.push("--tags");
|
|
763
|
+
args.push(filters.tags.join(","));
|
|
764
|
+
}
|
|
765
|
+
if (filters.tests) {
|
|
766
|
+
args.push("--tests");
|
|
767
|
+
args.push(filters.tests.join(","));
|
|
768
|
+
}
|
|
769
|
+
return args;
|
|
770
|
+
}
|
|
771
|
+
#clearScreen() {
|
|
772
|
+
if (this.options.clearScreen) process.stdout.write("\x1Bc");
|
|
773
|
+
}
|
|
774
|
+
async #runTests(port, hmrPort, filters) {
|
|
775
|
+
await this.#hooks.runner("testsStarting").run(this);
|
|
776
|
+
debug_default("running tests using \"%s\" file, options %O", this.scriptFile, this.options);
|
|
777
|
+
return new Promise(async (resolve) => {
|
|
778
|
+
const mergedFilters = {
|
|
779
|
+
...this.options.filters,
|
|
780
|
+
...filters
|
|
781
|
+
};
|
|
782
|
+
const scriptArgs = [
|
|
783
|
+
...this.#convertOptionsToArgs(),
|
|
784
|
+
...this.options.scriptArgs,
|
|
785
|
+
...this.#convertFiltersToArgs(mergedFilters)
|
|
786
|
+
];
|
|
787
|
+
this.#testsProcess = runNode(this.cwd, {
|
|
788
|
+
script: this.scriptFile,
|
|
789
|
+
reject: true,
|
|
790
|
+
env: {
|
|
791
|
+
PORT: port,
|
|
792
|
+
VITE_HMR_PORT: hmrPort,
|
|
793
|
+
...this.options.env
|
|
794
|
+
},
|
|
795
|
+
nodeArgs: this.options.nodeArgs,
|
|
796
|
+
scriptArgs
|
|
797
|
+
});
|
|
798
|
+
this.#testsProcess.then((result) => {
|
|
799
|
+
this.#hooks.runner("testsFinished").run(this).catch((error) => {
|
|
800
|
+
this.ui.logger.error("One of the \"testsFinished\" hooks failed");
|
|
801
|
+
this.ui.logger.fatal(error);
|
|
802
|
+
}).finally(() => {
|
|
803
|
+
if (!this.#watcher) {
|
|
804
|
+
this.#onClose?.(result.exitCode);
|
|
805
|
+
this.close();
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
}).catch((error) => {
|
|
809
|
+
if (!this.#watcher) {
|
|
810
|
+
this.#onError?.(error);
|
|
811
|
+
this.close();
|
|
812
|
+
} else this.ui.logger.info("Underlying HTTP server died. Still watching for changes");
|
|
813
|
+
}).finally(() => resolve());
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
#handleFileChange(relativePath, absolutePath, action) {
|
|
817
|
+
const file = this.#fileSystem.inspect(absolutePath, relativePath);
|
|
818
|
+
if (!file) return;
|
|
819
|
+
this.#clearScreen();
|
|
820
|
+
this.ui.logger.log(`${this.ui.colors.green(action)} ${relativePath}`);
|
|
821
|
+
if (file.fileType === "test") this.#reRunTests({ files: [relativePath] });
|
|
822
|
+
else this.#reRunTests();
|
|
823
|
+
}
|
|
824
|
+
#regenerateIndex(filePath, action) {
|
|
825
|
+
if (action === "add") return this.#indexGenerator.addFile(filePath);
|
|
826
|
+
return this.#indexGenerator.removeFile(filePath);
|
|
827
|
+
}
|
|
828
|
+
#registerServerRestartHooks() {
|
|
829
|
+
this.#hooks.add("fileAdded", (relativePath, absolutePath) => {
|
|
830
|
+
this.#regenerateIndex(absolutePath, "add");
|
|
831
|
+
this.#handleFileChange(relativePath, absolutePath, "add");
|
|
832
|
+
});
|
|
833
|
+
this.#hooks.add("fileChanged", (relativePath, absolutePath) => {
|
|
834
|
+
this.#regenerateIndex(absolutePath, "add");
|
|
835
|
+
this.#handleFileChange(relativePath, absolutePath, "update");
|
|
836
|
+
});
|
|
837
|
+
this.#hooks.add("fileRemoved", (relativePath, absolutePath) => {
|
|
838
|
+
this.#regenerateIndex(absolutePath, "delete");
|
|
839
|
+
this.#handleFileChange(relativePath, absolutePath, "delete");
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
onClose(callback) {
|
|
843
|
+
this.#onClose = callback;
|
|
844
|
+
return this;
|
|
845
|
+
}
|
|
846
|
+
onError(callback) {
|
|
847
|
+
this.#onError = callback;
|
|
848
|
+
return this;
|
|
849
|
+
}
|
|
850
|
+
async close() {
|
|
851
|
+
await this.#watcher?.close();
|
|
852
|
+
if (this.#testsProcess) {
|
|
853
|
+
this.#testsProcess.removeAllListeners();
|
|
854
|
+
this.#testsProcess.kill("SIGKILL");
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
async run() {
|
|
858
|
+
this.#stickyPort = String(await getPort(this.cwd));
|
|
859
|
+
this.#stickyHmrPort = String(await getRandomPort({ port: 24678 }));
|
|
860
|
+
this.#indexGenerator = new IndexGenerator(this.cwdPath, this.ui.logger);
|
|
861
|
+
this.#clearScreen();
|
|
862
|
+
this.ui.logger.info("loading hooks...");
|
|
863
|
+
this.#hooks = await loadHooks(this.options.hooks, [
|
|
864
|
+
"init",
|
|
865
|
+
"testsStarting",
|
|
866
|
+
"testsFinished"
|
|
867
|
+
]);
|
|
868
|
+
await this.#hooks.runner("init").run(this, this.#hooks, this.#indexGenerator);
|
|
869
|
+
this.#hooks.clear("init");
|
|
870
|
+
this.ui.logger.info("generating indexes...");
|
|
871
|
+
await this.#indexGenerator.generate();
|
|
872
|
+
this.ui.logger.info("booting application to run tests...");
|
|
873
|
+
await this.#runTests(this.#stickyPort, this.#stickyHmrPort);
|
|
874
|
+
}
|
|
875
|
+
async runAndWatch(options) {
|
|
876
|
+
const tsConfig = readTsConfig(this.cwdPath);
|
|
877
|
+
if (!tsConfig) {
|
|
878
|
+
this.#onError?.(new RuntimeException("Unable to parse tsconfig file"));
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
this.#stickyPort = String(await getPort(this.cwd));
|
|
882
|
+
this.#stickyHmrPort = String(getRandomPort({ port: 24678 }));
|
|
883
|
+
this.#indexGenerator = new IndexGenerator(this.cwdPath, this.ui.logger);
|
|
884
|
+
this.#fileSystem = new FileSystem(this.cwdPath, tsConfig, {
|
|
885
|
+
...this.options,
|
|
886
|
+
suites: this.options.suites?.filter((suite) => {
|
|
887
|
+
if (this.options.filters.suites) return this.options.filters.suites.includes(suite.name);
|
|
888
|
+
return true;
|
|
889
|
+
})
|
|
890
|
+
});
|
|
891
|
+
this.#clearScreen();
|
|
892
|
+
this.ui.logger.info("loading hooks...");
|
|
893
|
+
this.#hooks = await loadHooks(this.options.hooks, [
|
|
894
|
+
"init",
|
|
895
|
+
"testsStarting",
|
|
896
|
+
"testsFinished",
|
|
897
|
+
"fileAdded",
|
|
898
|
+
"fileChanged",
|
|
899
|
+
"fileRemoved"
|
|
900
|
+
]);
|
|
901
|
+
this.#registerServerRestartHooks();
|
|
902
|
+
await this.#hooks.runner("init").run(this, this.#hooks, this.#indexGenerator);
|
|
903
|
+
this.#hooks.clear("init");
|
|
904
|
+
this.ui.logger.info("generating indexes...");
|
|
905
|
+
await this.#indexGenerator.generate();
|
|
906
|
+
this.ui.logger.info("booting application to run tests...");
|
|
907
|
+
await this.#runTests(this.#stickyPort, this.#stickyHmrPort);
|
|
908
|
+
this.#watcher = watch({
|
|
909
|
+
usePolling: options?.poll ?? false,
|
|
910
|
+
cwd: this.cwdPath,
|
|
911
|
+
ignoreInitial: true,
|
|
912
|
+
ignored: (file, stats) => {
|
|
913
|
+
if (!stats) return false;
|
|
914
|
+
if (stats.isFile()) return !this.#fileSystem.shouldWatchFile(file);
|
|
915
|
+
return !this.#fileSystem.shouldWatchDirectory(file);
|
|
916
|
+
}
|
|
917
|
+
});
|
|
918
|
+
this.#watcher.on("ready", () => {
|
|
919
|
+
this.ui.logger.info("watching file system for changes...");
|
|
920
|
+
});
|
|
921
|
+
this.#watcher.on("error", (error) => {
|
|
922
|
+
this.ui.logger.warning("file system watcher failure");
|
|
923
|
+
this.ui.logger.fatal(error);
|
|
924
|
+
this.#onError?.(error);
|
|
925
|
+
this.#watcher?.close();
|
|
926
|
+
});
|
|
927
|
+
this.#watcher.on("add", (filePath) => {
|
|
928
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
929
|
+
const absolutePath = join(this.cwdPath, filePath);
|
|
930
|
+
this.#hooks.runner("fileAdded").run(relativePath, absolutePath, this);
|
|
931
|
+
});
|
|
932
|
+
this.#watcher.on("change", (filePath) => {
|
|
933
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
934
|
+
const absolutePath = join(this.cwdPath, filePath);
|
|
935
|
+
this.#hooks.runner("fileChanged").run(relativePath, absolutePath, {
|
|
936
|
+
source: "watcher",
|
|
937
|
+
fullReload: true,
|
|
938
|
+
hotReloaded: false
|
|
939
|
+
}, this);
|
|
940
|
+
});
|
|
941
|
+
this.#watcher.on("unlink", (filePath) => {
|
|
942
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
943
|
+
const absolutePath = join(this.cwdPath, filePath);
|
|
944
|
+
this.#hooks.runner("fileRemoved").run(relativePath, absolutePath, this);
|
|
945
|
+
});
|
|
946
|
+
}
|
|
1745
947
|
};
|
|
948
|
+
export { Bundler, CodemodException, DevServer, FileBuffer, SUPPORTED_PACKAGE_MANAGERS, TestRunner, VirtualFileSystem };
|