@adonisjs/assembler 8.0.0-next.3 → 8.0.0-next.30
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 +87 -59
- package/build/codemod_exception-vyN1VXuX.js +137 -0
- package/build/helpers-DDurYRsZ.js +72 -0
- package/build/index.d.ts +4 -0
- package/build/index.js +925 -1319
- package/build/main-BeV45LeF.js +246 -0
- package/build/main-CknPN3rJ.js +188 -0
- package/build/src/bundler.d.ts +44 -3
- package/build/src/code_scanners/routes_scanner/main.d.ts +63 -11
- package/build/src/code_scanners/routes_scanner/main.js +4 -0
- package/build/src/code_scanners/routes_scanner/validator_extractor.d.ts +12 -4
- package/build/src/code_transformer/main.d.ts +53 -43
- package/build/src/code_transformer/main.js +354 -599
- package/build/src/code_transformer/rc_file_transformer.d.ts +83 -5
- package/build/src/debug.d.ts +13 -1
- package/build/src/dev_server.d.ts +92 -17
- package/build/src/exceptions/codemod_exception.d.ts +178 -0
- package/build/src/file_buffer.d.ts +87 -0
- package/build/src/file_system.d.ts +46 -8
- package/build/src/helpers.d.ts +79 -4
- package/build/src/helpers.js +2 -0
- package/build/src/index_generator/main.d.ts +68 -0
- package/build/src/index_generator/main.js +3 -0
- package/build/src/index_generator/source.d.ts +60 -0
- package/build/src/paths_resolver.d.ts +29 -3
- package/build/src/shortcuts_manager.d.ts +42 -4
- package/build/src/test_runner.d.ts +57 -12
- package/build/src/types/code_scanners.d.ts +160 -30
- package/build/src/types/code_transformer.d.ts +69 -19
- package/build/src/types/common.d.ts +233 -55
- package/build/src/types/hooks.d.ts +238 -22
- package/build/src/types/main.d.ts +15 -1
- package/build/src/types/main.js +1 -0
- package/build/src/utils.d.ts +96 -15
- package/build/src/virtual_file_system.d.ts +112 -0
- package/build/virtual_file_system-bGeoWsK-.js +285 -0
- package/package.json +46 -36
- package/build/chunk-RR4HCA4M.js +0 -7
- package/build/src/ast_file_system.d.ts +0 -17
package/build/index.js
CHANGED
|
@@ -1,277 +1,93 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
} from "./
|
|
4
|
-
|
|
5
|
-
|
|
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, t as IndexGenerator } from "./main-CknPN3rJ.js";
|
|
3
|
+
import { t as RoutesScanner } from "./main-BeV45LeF.js";
|
|
4
|
+
import "./helpers-DDurYRsZ.js";
|
|
5
|
+
import { t as CodemodException } from "./codemod_exception-vyN1VXuX.js";
|
|
6
6
|
import dedent from "dedent";
|
|
7
|
-
import fs from "fs/promises";
|
|
7
|
+
import fs, { readFile, unlink } from "node:fs/promises";
|
|
8
8
|
import { cliui } from "@poppinss/cliui";
|
|
9
|
-
import { fileURLToPath
|
|
10
|
-
import { join as join2, relative as relative2 } from "path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
11
10
|
import string from "@poppinss/utils/string";
|
|
11
|
+
import { join, relative } from "node:path/posix";
|
|
12
12
|
import { detectPackageManager } from "@antfu/install-pkg";
|
|
13
|
-
|
|
14
|
-
// src/utils.ts
|
|
15
|
-
import Cache from "tmp-cache";
|
|
16
|
-
import { isJunk } from "junk";
|
|
17
|
-
import fastGlob from "fast-glob";
|
|
18
|
-
import Hooks from "@poppinss/hooks";
|
|
19
|
-
import { existsSync } from "fs";
|
|
20
13
|
import getRandomPort from "get-port";
|
|
21
|
-
import
|
|
22
|
-
import
|
|
23
|
-
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (parsedConfig.errors.length) {
|
|
50
|
-
const compilerHost = ts.createCompilerHost({});
|
|
51
|
-
console.log(ts.formatDiagnosticsWithColorAndContext(parsedConfig.errors, compilerHost));
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
return parsedConfig;
|
|
55
|
-
}
|
|
56
|
-
function runNode(cwd, options) {
|
|
57
|
-
const childProcess = execaNode(options.script, options.scriptArgs, {
|
|
58
|
-
nodeOptions: DEFAULT_NODE_ARGS.concat(options.nodeArgs),
|
|
59
|
-
preferLocal: true,
|
|
60
|
-
windowsHide: false,
|
|
61
|
-
localDir: cwd,
|
|
62
|
-
cwd,
|
|
63
|
-
reject: options.reject ?? false,
|
|
64
|
-
buffer: false,
|
|
65
|
-
stdio: options.stdio || "inherit",
|
|
66
|
-
env: {
|
|
67
|
-
...options.stdio === "pipe" ? { FORCE_COLOR: "true" } : {},
|
|
68
|
-
...options.env
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
return childProcess;
|
|
72
|
-
}
|
|
73
|
-
function run(cwd, options) {
|
|
74
|
-
const childProcess = execa(options.script, options.scriptArgs, {
|
|
75
|
-
preferLocal: true,
|
|
76
|
-
windowsHide: false,
|
|
77
|
-
localDir: cwd,
|
|
78
|
-
cwd,
|
|
79
|
-
buffer: false,
|
|
80
|
-
stdio: options.stdio || "inherit",
|
|
81
|
-
env: {
|
|
82
|
-
...options.stdio === "pipe" ? { FORCE_COLOR: "true" } : {},
|
|
83
|
-
...options.env
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
return childProcess;
|
|
87
|
-
}
|
|
88
|
-
function watch(options) {
|
|
89
|
-
return chokidar.watch(["."], options);
|
|
90
|
-
}
|
|
91
|
-
async function getPort(cwd) {
|
|
92
|
-
if (process.env.PORT) {
|
|
93
|
-
return getRandomPort({ port: Number(process.env.PORT) });
|
|
94
|
-
}
|
|
95
|
-
const files = await new EnvLoader(cwd).load();
|
|
96
|
-
for (let file of files) {
|
|
97
|
-
const envVariables = await new EnvParser(file.contents).parse();
|
|
98
|
-
if (envVariables.PORT) {
|
|
99
|
-
return getRandomPort({ port: Number(envVariables.PORT) });
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
return getRandomPort({ port: 3333 });
|
|
103
|
-
}
|
|
104
|
-
async function copyFiles(files, cwd, outDir) {
|
|
105
|
-
const { paths, patterns } = files.reduce(
|
|
106
|
-
(result, file) => {
|
|
107
|
-
if (fastGlob.isDynamicPattern(file)) {
|
|
108
|
-
result.patterns.push(file);
|
|
109
|
-
return result;
|
|
110
|
-
}
|
|
111
|
-
if (existsSync(join(cwd, file))) {
|
|
112
|
-
result.paths.push(file);
|
|
113
|
-
}
|
|
114
|
-
return result;
|
|
115
|
-
},
|
|
116
|
-
{ patterns: [], paths: [] }
|
|
117
|
-
);
|
|
118
|
-
debug_default("copyFiles inputs: %O, paths: %O, patterns: %O", files, paths, patterns);
|
|
119
|
-
const filePaths = paths.concat(await fastGlob(patterns, { cwd, dot: true })).filter((file) => {
|
|
120
|
-
return !isJunk(basename(file));
|
|
121
|
-
});
|
|
122
|
-
debug_default('copying files %O to destination "%s"', filePaths, outDir);
|
|
123
|
-
const copyPromises = filePaths.map(async (file) => {
|
|
124
|
-
const src = isAbsolute(file) ? file : join(cwd, file);
|
|
125
|
-
const dest = join(outDir, relative(cwd, src));
|
|
126
|
-
await mkdir(dirname(dest), { recursive: true });
|
|
127
|
-
return copyFile(src, dest);
|
|
128
|
-
});
|
|
129
|
-
return await Promise.all(copyPromises);
|
|
130
|
-
}
|
|
131
|
-
function memoize(fn, maxKeys) {
|
|
132
|
-
const cache = new Cache({ max: maxKeys });
|
|
133
|
-
return (input) => {
|
|
134
|
-
if (cache.has(input)) {
|
|
135
|
-
return cache.get(input);
|
|
136
|
-
}
|
|
137
|
-
return fn(input);
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
async function loadHooks(rcFileHooks, names) {
|
|
141
|
-
const groups = names.map((name) => {
|
|
142
|
-
return {
|
|
143
|
-
group: name,
|
|
144
|
-
hooks: rcFileHooks?.[name] ?? []
|
|
145
|
-
};
|
|
146
|
-
});
|
|
147
|
-
const hooks = new Hooks();
|
|
148
|
-
for (const { group, hooks: collection } of groups) {
|
|
149
|
-
for (const item of collection) {
|
|
150
|
-
hooks.add(group, await importDefault(item));
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
return hooks;
|
|
154
|
-
}
|
|
155
|
-
function throttle(fn, name) {
|
|
156
|
-
name = name || "throttled";
|
|
157
|
-
let isBusy = false;
|
|
158
|
-
let hasQueuedCalls = false;
|
|
159
|
-
let lastCallArgs;
|
|
160
|
-
async function throttled(...args) {
|
|
161
|
-
if (isBusy) {
|
|
162
|
-
debug_default('ignoring "%s" invocation as current execution is in progress', name);
|
|
163
|
-
hasQueuedCalls = true;
|
|
164
|
-
lastCallArgs = args;
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
isBusy = true;
|
|
168
|
-
debug_default('executing "%s" function', name);
|
|
169
|
-
await fn(...args);
|
|
170
|
-
isBusy = false;
|
|
171
|
-
if (hasQueuedCalls) {
|
|
172
|
-
hasQueuedCalls = false;
|
|
173
|
-
debug_default('resuming and running latest "%s" invocation', name);
|
|
174
|
-
await throttled(...lastCallArgs);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
return throttled;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// src/bundler.ts
|
|
181
|
-
var SUPPORTED_PACKAGE_MANAGERS = {
|
|
182
|
-
"npm": {
|
|
183
|
-
packageManagerFiles: ["package-lock.json"],
|
|
184
|
-
installCommand: 'npm ci --omit="dev"'
|
|
185
|
-
},
|
|
186
|
-
"yarn": {
|
|
187
|
-
packageManagerFiles: ["yarn.lock"],
|
|
188
|
-
installCommand: "yarn install --production"
|
|
189
|
-
},
|
|
190
|
-
"yarn@berry": {
|
|
191
|
-
packageManagerFiles: ["yarn.lock", ".yarn/**/*", ".yarnrc.yml"],
|
|
192
|
-
installCommand: "yarn workspaces focus --production"
|
|
193
|
-
},
|
|
194
|
-
"pnpm": {
|
|
195
|
-
packageManagerFiles: ["pnpm-lock.yaml"],
|
|
196
|
-
installCommand: "pnpm i --prod"
|
|
197
|
-
},
|
|
198
|
-
"bun": {
|
|
199
|
-
packageManagerFiles: ["bun.lockb"],
|
|
200
|
-
installCommand: "bun install --production"
|
|
201
|
-
}
|
|
14
|
+
import picomatch from "picomatch";
|
|
15
|
+
import prettyHrtime from "pretty-hrtime";
|
|
16
|
+
import { RuntimeException } from "@poppinss/utils/exception";
|
|
17
|
+
const SUPPORTED_PACKAGE_MANAGERS = {
|
|
18
|
+
"npm": {
|
|
19
|
+
packageManagerFiles: ["package-lock.json"],
|
|
20
|
+
installCommand: "npm ci --omit=\"dev\""
|
|
21
|
+
},
|
|
22
|
+
"yarn": {
|
|
23
|
+
packageManagerFiles: ["yarn.lock"],
|
|
24
|
+
installCommand: "yarn install --production"
|
|
25
|
+
},
|
|
26
|
+
"yarn@berry": {
|
|
27
|
+
packageManagerFiles: [
|
|
28
|
+
"yarn.lock",
|
|
29
|
+
".yarn/**/*",
|
|
30
|
+
".yarnrc.yml"
|
|
31
|
+
],
|
|
32
|
+
installCommand: "yarn workspaces focus --production"
|
|
33
|
+
},
|
|
34
|
+
"pnpm": {
|
|
35
|
+
packageManagerFiles: ["pnpm-lock.yaml"],
|
|
36
|
+
installCommand: "pnpm i --prod"
|
|
37
|
+
},
|
|
38
|
+
"bun": {
|
|
39
|
+
packageManagerFiles: ["bun.lockb"],
|
|
40
|
+
installCommand: "bun install --production"
|
|
41
|
+
}
|
|
202
42
|
};
|
|
203
43
|
var Bundler = class {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Detect the package manager used by the project
|
|
254
|
-
*/
|
|
255
|
-
async #detectPackageManager() {
|
|
256
|
-
const pkgManager = await detectPackageManager(this.#cwdPath);
|
|
257
|
-
if (pkgManager === "deno") {
|
|
258
|
-
return "npm";
|
|
259
|
-
}
|
|
260
|
-
if (pkgManager === "pnpm@6") {
|
|
261
|
-
return "pnpm";
|
|
262
|
-
}
|
|
263
|
-
return pkgManager;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Rewrite the ace file since the original one
|
|
267
|
-
* is importing ts-node which is not installed
|
|
268
|
-
* in a production environment.
|
|
269
|
-
*/
|
|
270
|
-
async #createAceFile(outDir) {
|
|
271
|
-
const aceFileLocation = join2(outDir, "ace.js");
|
|
272
|
-
const aceFileContent = dedent(
|
|
273
|
-
/* JavaScript */
|
|
274
|
-
`
|
|
44
|
+
#ts;
|
|
45
|
+
#hooks;
|
|
46
|
+
#indexGenerator;
|
|
47
|
+
ui = cliui();
|
|
48
|
+
cwd;
|
|
49
|
+
cwdPath;
|
|
50
|
+
options;
|
|
51
|
+
constructor(cwd, ts, options) {
|
|
52
|
+
this.cwd = cwd;
|
|
53
|
+
this.options = options;
|
|
54
|
+
this.cwdPath = string.toUnixSlash(fileURLToPath(this.cwd));
|
|
55
|
+
this.#ts = ts;
|
|
56
|
+
}
|
|
57
|
+
#getRelativeName(filePath) {
|
|
58
|
+
return string.toUnixSlash(relative(this.cwdPath, filePath));
|
|
59
|
+
}
|
|
60
|
+
async #cleanupBuildDirectory(outDir) {
|
|
61
|
+
await fs.rm(outDir, {
|
|
62
|
+
recursive: true,
|
|
63
|
+
force: true,
|
|
64
|
+
maxRetries: 5
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async #runTsc(outDir) {
|
|
68
|
+
try {
|
|
69
|
+
await run(this.cwd, {
|
|
70
|
+
stdio: "inherit",
|
|
71
|
+
script: "tsc",
|
|
72
|
+
scriptArgs: ["--outDir", outDir]
|
|
73
|
+
});
|
|
74
|
+
return true;
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
async #copyMetaFiles(outDir, additionalFilesToCopy) {
|
|
80
|
+
await copyFiles((this.options.metaFiles || []).map((file) => file.pattern).concat(additionalFilesToCopy), this.cwdPath, outDir);
|
|
81
|
+
}
|
|
82
|
+
async #detectPackageManager() {
|
|
83
|
+
const pkgManager = await detectPackageManager(this.cwdPath);
|
|
84
|
+
if (pkgManager === "deno") return "npm";
|
|
85
|
+
if (pkgManager === "pnpm@6") return "pnpm";
|
|
86
|
+
return pkgManager;
|
|
87
|
+
}
|
|
88
|
+
async #createAceFile(outDir) {
|
|
89
|
+
const aceFileLocation = join(outDir, "ace.js");
|
|
90
|
+
const aceFileContent = dedent(`
|
|
275
91
|
/**
|
|
276
92
|
* This file is auto-generated by the build process.
|
|
277
93
|
* If you had any custom code inside this file, then
|
|
@@ -279,1063 +95,853 @@ var Bundler = class {
|
|
|
279
95
|
*/
|
|
280
96
|
|
|
281
97
|
await import('./bin/console.js')
|
|
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
|
-
|
|
325
|
-
|
|
326
|
-
const displayMessage = this.ui.instructions().heading("Run the following commands to start the server in production");
|
|
327
|
-
await this.#hooks.runner("buildFinished").run(this, displayMessage);
|
|
328
|
-
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();
|
|
329
|
-
return true;
|
|
330
|
-
}
|
|
98
|
+
`);
|
|
99
|
+
await fs.writeFile(aceFileLocation, aceFileContent);
|
|
100
|
+
this.ui.logger.info("created ace file", { suffix: this.#getRelativeName(aceFileLocation) });
|
|
101
|
+
}
|
|
102
|
+
async bundle(stopOnError = true, client) {
|
|
103
|
+
this.packageManager = client ?? await this.#detectPackageManager() ?? "npm";
|
|
104
|
+
const config = parseConfig(this.cwd, this.#ts);
|
|
105
|
+
if (!config) return false;
|
|
106
|
+
this.ui.logger.info("loading hooks...");
|
|
107
|
+
this.#hooks = await loadHooks(this.options.hooks, [
|
|
108
|
+
"init",
|
|
109
|
+
"buildStarting",
|
|
110
|
+
"buildFinished"
|
|
111
|
+
]);
|
|
112
|
+
this.#indexGenerator = new IndexGenerator(this.cwdPath, this.ui.logger);
|
|
113
|
+
await this.#hooks.runner("init").run(this, this.#hooks, this.#indexGenerator);
|
|
114
|
+
this.#hooks.clear("init");
|
|
115
|
+
this.ui.logger.info("generating indexes...");
|
|
116
|
+
await this.#indexGenerator.generate();
|
|
117
|
+
const outDir = config.options.outDir || fileURLToPath(new URL("build/", this.cwd));
|
|
118
|
+
this.ui.logger.info("cleaning up output directory", { suffix: this.#getRelativeName(outDir) });
|
|
119
|
+
await this.#cleanupBuildDirectory(outDir);
|
|
120
|
+
await this.#hooks.runner("buildStarting").run(this);
|
|
121
|
+
this.ui.logger.info("compiling typescript source", { suffix: "tsc" });
|
|
122
|
+
const buildCompleted = await this.#runTsc(outDir);
|
|
123
|
+
await this.#createAceFile(outDir);
|
|
124
|
+
if (!buildCompleted && stopOnError) {
|
|
125
|
+
await this.#cleanupBuildDirectory(outDir);
|
|
126
|
+
const instructions = this.ui.sticker().fullScreen().drawBorder((borderChar, colors) => colors.red(borderChar));
|
|
127
|
+
instructions.add(this.ui.colors.red("Cannot complete the build process as there are TypeScript errors."));
|
|
128
|
+
instructions.add(this.ui.colors.red("Use \"--ignore-ts-errors\" flag to ignore TypeScript errors and continue the build."));
|
|
129
|
+
this.ui.logger.logError(instructions.prepare());
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
const pkgFiles = ["package.json", ...SUPPORTED_PACKAGE_MANAGERS[this.packageManager].packageManagerFiles];
|
|
133
|
+
this.ui.logger.info("copying meta files to the output directory");
|
|
134
|
+
await this.#copyMetaFiles(outDir, pkgFiles);
|
|
135
|
+
this.ui.logger.success("build completed");
|
|
136
|
+
this.ui.logger.log("");
|
|
137
|
+
const displayMessage = this.ui.instructions().heading("Run the following commands to start the server in production");
|
|
138
|
+
await this.#hooks.runner("buildFinished").run(this, displayMessage);
|
|
139
|
+
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();
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
331
142
|
};
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
import string2 from "@poppinss/utils/string";
|
|
345
|
-
var DEFAULT_INCLUDES = ["**/*"];
|
|
346
|
-
var ALWAYS_EXCLUDE = [".git/**", "coverage/**", ".github/**"];
|
|
347
|
-
var DEFAULT_EXCLUDES = ["node_modules/**", "bower_components/**", "jspm_packages/**"];
|
|
143
|
+
const DEFAULT_INCLUDES = ["**/*"];
|
|
144
|
+
const ALWAYS_EXCLUDE = [
|
|
145
|
+
".git/**",
|
|
146
|
+
"coverage/**",
|
|
147
|
+
".github/**",
|
|
148
|
+
".adonisjs/**"
|
|
149
|
+
];
|
|
150
|
+
const DEFAULT_EXCLUDES = [
|
|
151
|
+
"node_modules/**",
|
|
152
|
+
"bower_components/**",
|
|
153
|
+
"jspm_packages/**"
|
|
154
|
+
];
|
|
348
155
|
var FileSystem = class {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
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
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
if (absolutePath === this.#cwd) {
|
|
461
|
-
debug_default("watching project root");
|
|
462
|
-
return true;
|
|
463
|
-
}
|
|
464
|
-
const relativePath = string2.toUnixSlash(relative3(this.#cwd, absolutePath));
|
|
465
|
-
if (this.#isExcluded(relativePath)) {
|
|
466
|
-
debug_default('watching "%s"', absolutePath);
|
|
467
|
-
return false;
|
|
468
|
-
}
|
|
469
|
-
return true;
|
|
470
|
-
});
|
|
471
|
-
constructor(cwd, tsConfig, rcFile) {
|
|
472
|
-
this.#cwd = string2.toUnixSlash(typeof cwd === "string" ? cwd : fileURLToPath3(cwd));
|
|
473
|
-
this.#tsConfig = tsConfig;
|
|
474
|
-
const files = tsConfig.fileNames;
|
|
475
|
-
const metaFiles = rcFile.metaFiles ?? [];
|
|
476
|
-
const testSuites = rcFile.suites ?? [];
|
|
477
|
-
const outDir = tsConfig.raw.compilerOptions?.outDir;
|
|
478
|
-
files.forEach((file) => this.#scannedTypeScriptFiles.add(string2.toUnixSlash(file)));
|
|
479
|
-
this.#includes = tsConfig.raw.include || DEFAULT_INCLUDES;
|
|
480
|
-
this.#excludes = ALWAYS_EXCLUDE.concat(
|
|
481
|
-
tsConfig.raw.exclude || (outDir ? DEFAULT_EXCLUDES.concat(outDir) : DEFAULT_EXCLUDES)
|
|
482
|
-
);
|
|
483
|
-
this.#isMetaFileWithReloadsEnabled = picomatch(
|
|
484
|
-
metaFiles.filter((file) => !!file.reloadServer).map((file) => file.pattern),
|
|
485
|
-
{
|
|
486
|
-
cwd: this.#cwd
|
|
487
|
-
}
|
|
488
|
-
);
|
|
489
|
-
this.#isMetaFileWithReloadsDisabled = picomatch(
|
|
490
|
-
metaFiles.filter((file) => !file.reloadServer).map((file) => file.pattern),
|
|
491
|
-
{
|
|
492
|
-
cwd: this.#cwd
|
|
493
|
-
}
|
|
494
|
-
);
|
|
495
|
-
this.#isTestFile = picomatch(
|
|
496
|
-
testSuites.flatMap((suite) => suite.files),
|
|
497
|
-
{
|
|
498
|
-
cwd: this.#cwd
|
|
499
|
-
}
|
|
500
|
-
);
|
|
501
|
-
this.#isIncluded = picomatch(this.#includes, {
|
|
502
|
-
cwd: this.#cwd
|
|
503
|
-
});
|
|
504
|
-
this.#isExcluded = picomatch(this.#excludes, {
|
|
505
|
-
cwd: this.#cwd
|
|
506
|
-
});
|
|
507
|
-
debug_default("initiating file system %O", {
|
|
508
|
-
includes: this.#includes,
|
|
509
|
-
excludes: this.#includes,
|
|
510
|
-
outDir,
|
|
511
|
-
files,
|
|
512
|
-
metaFiles,
|
|
513
|
-
testSuites
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
/**
|
|
517
|
-
* Returns a boolean telling if a file path is a script file or not.
|
|
518
|
-
*
|
|
519
|
-
* - Files ending with ".ts", ".tsx" are considered are script files.
|
|
520
|
-
* - Files ending with ".js" with "allowJs" option enabled are considered are script files.
|
|
521
|
-
* - Files ending with ".json" with "resolveJsonModule" option enabled are considered are script files.
|
|
522
|
-
*/
|
|
523
|
-
#isScriptFile(relativePath) {
|
|
524
|
-
if ((relativePath.endsWith(".ts") || relativePath.endsWith(".tsx")) && !relativePath.endsWith(".d.ts")) {
|
|
525
|
-
return true;
|
|
526
|
-
}
|
|
527
|
-
if (this.#tsConfig.options.allowJs && relativePath.endsWith(".js")) {
|
|
528
|
-
return true;
|
|
529
|
-
}
|
|
530
|
-
if (this.#tsConfig.options.resolveJsonModule && relativePath.endsWith(".json")) {
|
|
531
|
-
return true;
|
|
532
|
-
}
|
|
533
|
-
return false;
|
|
534
|
-
}
|
|
535
|
-
/**
|
|
536
|
-
* Check if the file path is part of the backend TypeScript project. We use
|
|
537
|
-
* tsconfig "includes", "excludes", and "files" paths to test if the file
|
|
538
|
-
* should be considered or not.
|
|
539
|
-
*/
|
|
540
|
-
#isPartOfBackendProject(relativePath) {
|
|
541
|
-
if (this.#isExcluded(relativePath)) {
|
|
542
|
-
debug_default('excluded by tsconfig "%s"', relativePath);
|
|
543
|
-
return false;
|
|
544
|
-
}
|
|
545
|
-
if (this.#isIncluded(relativePath)) {
|
|
546
|
-
debug_default('included by tsconfig "%s"', relativePath);
|
|
547
|
-
return true;
|
|
548
|
-
}
|
|
549
|
-
return false;
|
|
550
|
-
}
|
|
551
|
-
/**
|
|
552
|
-
* Returns true if the file should be watched. Chokidar sends
|
|
553
|
-
* absolute unix paths to the ignored callback.
|
|
554
|
-
*
|
|
555
|
-
* You must use "shouldWatchDirectory" method for directories and call
|
|
556
|
-
* this method for files only.
|
|
557
|
-
*/
|
|
558
|
-
shouldWatchFile(absolutePath) {
|
|
559
|
-
return this.inspect(relative3(this.#cwd, absolutePath)) !== null;
|
|
560
|
-
}
|
|
156
|
+
#cwd;
|
|
157
|
+
#tsConfig;
|
|
158
|
+
#scannedTypeScriptFiles = /* @__PURE__ */ new Set();
|
|
159
|
+
#isIncluded;
|
|
160
|
+
#isExcluded;
|
|
161
|
+
#isMetaFileWithReloadsEnabled;
|
|
162
|
+
#isMetaFileWithReloadsDisabled;
|
|
163
|
+
#isTestFile;
|
|
164
|
+
#includes;
|
|
165
|
+
#excludes;
|
|
166
|
+
get includes() {
|
|
167
|
+
return this.#includes;
|
|
168
|
+
}
|
|
169
|
+
get excludes() {
|
|
170
|
+
return this.#excludes;
|
|
171
|
+
}
|
|
172
|
+
inspect = memoize((absolutePath, relativePath) => {
|
|
173
|
+
relativePath = relativePath ?? relative(this.#cwd, absolutePath);
|
|
174
|
+
if (this.#isScriptFile(relativePath) && (this.#scannedTypeScriptFiles.has(absolutePath) || this.#isPartOfBackendProject(relativePath))) {
|
|
175
|
+
debug_default("backend project file \"%s\"", relativePath);
|
|
176
|
+
const isTestFile = this.#isTestFile(relativePath);
|
|
177
|
+
return {
|
|
178
|
+
fileType: isTestFile ? "test" : "script",
|
|
179
|
+
reloadServer: !isTestFile,
|
|
180
|
+
unixRelativePath: relativePath,
|
|
181
|
+
unixAbsolutePath: absolutePath
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (this.#isMetaFileWithReloadsEnabled(relativePath)) {
|
|
185
|
+
debug_default("meta file \"%s\"", relativePath);
|
|
186
|
+
return {
|
|
187
|
+
fileType: "meta",
|
|
188
|
+
reloadServer: true,
|
|
189
|
+
unixRelativePath: relativePath,
|
|
190
|
+
unixAbsolutePath: absolutePath
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (this.#isMetaFileWithReloadsDisabled(relativePath)) {
|
|
194
|
+
debug_default("meta file \"%s\"", relativePath);
|
|
195
|
+
return {
|
|
196
|
+
fileType: "meta",
|
|
197
|
+
reloadServer: false,
|
|
198
|
+
unixRelativePath: relativePath,
|
|
199
|
+
unixAbsolutePath: absolutePath
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
debug_default("ignored file \"%s\"", relativePath);
|
|
203
|
+
return null;
|
|
204
|
+
});
|
|
205
|
+
shouldWatchDirectory = memoize((absolutePath) => {
|
|
206
|
+
if (absolutePath === this.#cwd) {
|
|
207
|
+
debug_default("watching project root");
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
const relativePath = relative(this.#cwd, absolutePath);
|
|
211
|
+
if (this.#isExcluded(relativePath)) {
|
|
212
|
+
debug_default("watching \"%s\"", absolutePath);
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
return true;
|
|
216
|
+
});
|
|
217
|
+
constructor(cwd, tsConfig, rcFile) {
|
|
218
|
+
this.#cwd = cwd;
|
|
219
|
+
this.#tsConfig = tsConfig;
|
|
220
|
+
const files = tsConfig.config.files ?? [];
|
|
221
|
+
const metaFiles = rcFile.metaFiles ?? [];
|
|
222
|
+
const testSuites = rcFile.suites ?? [];
|
|
223
|
+
const outDir = tsConfig.config.compilerOptions?.outDir;
|
|
224
|
+
for (const file of files) this.#scannedTypeScriptFiles.add(string.toUnixSlash(file));
|
|
225
|
+
this.#includes = tsConfig.config.include || DEFAULT_INCLUDES;
|
|
226
|
+
this.#excludes = ALWAYS_EXCLUDE.concat(tsConfig.config.exclude || (outDir ? DEFAULT_EXCLUDES.concat(outDir) : DEFAULT_EXCLUDES));
|
|
227
|
+
const metaFilesWithReloads = [];
|
|
228
|
+
const metaFilesWithoutReloads = [];
|
|
229
|
+
for (const file of metaFiles) if (file.reloadServer) metaFilesWithReloads.push(file.pattern);
|
|
230
|
+
else metaFilesWithoutReloads.push(file.pattern);
|
|
231
|
+
const testFilePatterns = testSuites.flatMap((suite) => suite.files);
|
|
232
|
+
const picomatcchOptions = { cwd: this.#cwd };
|
|
233
|
+
this.#isMetaFileWithReloadsEnabled = picomatch(metaFilesWithReloads, picomatcchOptions);
|
|
234
|
+
this.#isMetaFileWithReloadsDisabled = picomatch(metaFilesWithoutReloads, picomatcchOptions);
|
|
235
|
+
this.#isTestFile = picomatch(testFilePatterns, picomatcchOptions);
|
|
236
|
+
this.#isIncluded = picomatch(this.#includes, picomatcchOptions);
|
|
237
|
+
this.#isExcluded = picomatch(this.#excludes, picomatcchOptions);
|
|
238
|
+
debug_default("initiating file system %O", {
|
|
239
|
+
includes: this.#includes,
|
|
240
|
+
excludes: this.#excludes,
|
|
241
|
+
outDir,
|
|
242
|
+
files,
|
|
243
|
+
metaFiles,
|
|
244
|
+
testSuites
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
#isScriptFile(relativePath) {
|
|
248
|
+
if ((relativePath.endsWith(".ts") || relativePath.endsWith(".tsx")) && !relativePath.endsWith(".d.ts")) return true;
|
|
249
|
+
if (this.#tsConfig.config.compilerOptions?.allowJs && relativePath.endsWith(".js")) return true;
|
|
250
|
+
if (this.#tsConfig.config.compilerOptions?.resolveJsonModule && relativePath.endsWith(".json")) return true;
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
#isPartOfBackendProject(relativePath) {
|
|
254
|
+
if (this.#isExcluded(relativePath)) {
|
|
255
|
+
debug_default("excluded by tsconfig \"%s\"", relativePath);
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
if (this.#isIncluded(relativePath)) {
|
|
259
|
+
debug_default("included by tsconfig \"%s\"", relativePath);
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
shouldWatchFile(absolutePath) {
|
|
265
|
+
return this.inspect(absolutePath) !== null;
|
|
266
|
+
}
|
|
561
267
|
};
|
|
562
|
-
|
|
563
|
-
// src/shortcuts_manager.ts
|
|
564
268
|
var ShortcutsManager = class {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
this.#logger.log("");
|
|
636
|
-
this.#logger.info(`Opening ${this.#serverUrl}...`);
|
|
637
|
-
const { default: open } = await import("open");
|
|
638
|
-
open(this.#serverUrl);
|
|
639
|
-
}
|
|
640
|
-
/**
|
|
641
|
-
* Show available keyboard shortcuts
|
|
642
|
-
*/
|
|
643
|
-
showHelp() {
|
|
644
|
-
this.#logger.log("");
|
|
645
|
-
this.#logger.log("Available shortcuts:");
|
|
646
|
-
this.#shortcuts.forEach(({ key, description }) => this.#logger.log(`\xB7 ${key}: ${description}`));
|
|
647
|
-
}
|
|
648
|
-
/**
|
|
649
|
-
* Cleanup keyboard shortcuts
|
|
650
|
-
*/
|
|
651
|
-
cleanup() {
|
|
652
|
-
if (!process.stdin.isTTY) {
|
|
653
|
-
return;
|
|
654
|
-
}
|
|
655
|
-
process.stdin.setRawMode(false);
|
|
656
|
-
process.stdin.removeListener("data", this.#keyPressHandler);
|
|
657
|
-
this.#keyPressHandler = void 0;
|
|
658
|
-
}
|
|
269
|
+
#logger;
|
|
270
|
+
#callbacks;
|
|
271
|
+
#serverUrl;
|
|
272
|
+
#keyPressHandler;
|
|
273
|
+
#shortcuts = [
|
|
274
|
+
{
|
|
275
|
+
key: "r",
|
|
276
|
+
description: "restart server",
|
|
277
|
+
handler: () => {
|
|
278
|
+
this.#logger.log("");
|
|
279
|
+
this.#logger.info("Manual restart triggered...");
|
|
280
|
+
this.#callbacks.onRestart();
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
key: "c",
|
|
285
|
+
description: "clear console",
|
|
286
|
+
handler: () => {
|
|
287
|
+
this.#callbacks.onClear();
|
|
288
|
+
this.#logger.info("Console cleared");
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
key: "o",
|
|
293
|
+
description: "open in browser",
|
|
294
|
+
handler: () => this.#handleOpenBrowser()
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
key: "h",
|
|
298
|
+
description: "show this help",
|
|
299
|
+
handler: () => this.showHelp()
|
|
300
|
+
}
|
|
301
|
+
];
|
|
302
|
+
constructor(options) {
|
|
303
|
+
this.#logger = options.logger;
|
|
304
|
+
this.#callbacks = options.callbacks;
|
|
305
|
+
}
|
|
306
|
+
setServerUrl(url) {
|
|
307
|
+
this.#serverUrl = url;
|
|
308
|
+
}
|
|
309
|
+
setup() {
|
|
310
|
+
if (!process.stdin.isTTY) return;
|
|
311
|
+
process.stdin.setRawMode(true);
|
|
312
|
+
this.#keyPressHandler = (data) => this.#handleKeyPress(data.toString());
|
|
313
|
+
process.stdin.on("data", this.#keyPressHandler);
|
|
314
|
+
}
|
|
315
|
+
#handleKeyPress(key) {
|
|
316
|
+
if (key === "" || key === "") return this.#callbacks.onQuit();
|
|
317
|
+
const shortcut = this.#shortcuts.find((s) => s.key === key);
|
|
318
|
+
if (shortcut) shortcut.handler();
|
|
319
|
+
}
|
|
320
|
+
async #handleOpenBrowser() {
|
|
321
|
+
this.#logger.log("");
|
|
322
|
+
this.#logger.info(`Opening ${this.#serverUrl}...`);
|
|
323
|
+
const { default: open } = await import("open");
|
|
324
|
+
open(this.#serverUrl);
|
|
325
|
+
}
|
|
326
|
+
showHelp() {
|
|
327
|
+
this.#logger.log("");
|
|
328
|
+
this.#logger.log("Available shortcuts:");
|
|
329
|
+
this.#shortcuts.forEach(({ key, description }) => this.#logger.log(`· ${key}: ${description}`));
|
|
330
|
+
}
|
|
331
|
+
cleanup() {
|
|
332
|
+
if (!process.stdin.isTTY) return;
|
|
333
|
+
process.stdin.setRawMode(false);
|
|
334
|
+
process.stdin.pause();
|
|
335
|
+
process.stdin.unref();
|
|
336
|
+
process.stdin.removeListener("data", this.#keyPressHandler);
|
|
337
|
+
this.#keyPressHandler = void 0;
|
|
338
|
+
}
|
|
659
339
|
};
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
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
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
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
|
-
this.#watcher.on(
|
|
1026
|
-
"change",
|
|
1027
|
-
(filePath) => this.#hooks.runner("fileChanged").run(
|
|
1028
|
-
string3.toUnixSlash(filePath),
|
|
1029
|
-
{
|
|
1030
|
-
source: "watcher",
|
|
1031
|
-
fullReload: true,
|
|
1032
|
-
hotReloaded: false
|
|
1033
|
-
},
|
|
1034
|
-
this
|
|
1035
|
-
)
|
|
1036
|
-
);
|
|
1037
|
-
this.#watcher.on(
|
|
1038
|
-
"unlink",
|
|
1039
|
-
(filePath) => this.#hooks.runner("fileRemoved").run(string3.toUnixSlash(filePath), this)
|
|
1040
|
-
);
|
|
1041
|
-
}
|
|
340
|
+
var DevServer = class DevServer {
|
|
341
|
+
static #HOT_HOOK_FULL_RELOAD_INFO = {
|
|
342
|
+
source: "hot-hook",
|
|
343
|
+
fullReload: true,
|
|
344
|
+
hotReloaded: false
|
|
345
|
+
};
|
|
346
|
+
static #HOT_HOOK_INVALIDATED_INFO = {
|
|
347
|
+
source: "hot-hook",
|
|
348
|
+
fullReload: false,
|
|
349
|
+
hotReloaded: true
|
|
350
|
+
};
|
|
351
|
+
static #WATCHER_INFO = {
|
|
352
|
+
source: "watcher",
|
|
353
|
+
fullReload: true,
|
|
354
|
+
hotReloaded: false
|
|
355
|
+
};
|
|
356
|
+
#onError;
|
|
357
|
+
#onClose;
|
|
358
|
+
#stickyPort;
|
|
359
|
+
#stickyHmrPort;
|
|
360
|
+
#mode = "static";
|
|
361
|
+
#watcher;
|
|
362
|
+
#httpServer;
|
|
363
|
+
#isHttpServerAlive = false;
|
|
364
|
+
#shortcutsManager;
|
|
365
|
+
#fileSystem;
|
|
366
|
+
#indexGenerator;
|
|
367
|
+
#routesScanner;
|
|
368
|
+
#hooks;
|
|
369
|
+
ui = cliui();
|
|
370
|
+
#restartHTTPServer = throttle(async () => {
|
|
371
|
+
if (this.#httpServer) {
|
|
372
|
+
this.#httpServer.removeAllListeners();
|
|
373
|
+
this.#httpServer.kill("SIGKILL");
|
|
374
|
+
}
|
|
375
|
+
await this.#startHTTPServer(this.#stickyPort, this.#stickyHmrPort);
|
|
376
|
+
}, "restartHTTPServer");
|
|
377
|
+
#setupKeyboardShortcuts() {
|
|
378
|
+
this.#shortcutsManager = new ShortcutsManager({
|
|
379
|
+
logger: this.ui.logger,
|
|
380
|
+
callbacks: {
|
|
381
|
+
onRestart: () => this.#restartHTTPServer(),
|
|
382
|
+
onClear: () => this.#clearScreen(),
|
|
383
|
+
onQuit: () => this.close()
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
this.#shortcutsManager.setup();
|
|
387
|
+
}
|
|
388
|
+
#cleanupKeyboardShortcuts() {
|
|
389
|
+
this.#shortcutsManager?.cleanup();
|
|
390
|
+
}
|
|
391
|
+
get mode() {
|
|
392
|
+
return this.#mode;
|
|
393
|
+
}
|
|
394
|
+
scriptFile = "bin/server.ts";
|
|
395
|
+
cwd;
|
|
396
|
+
cwdPath;
|
|
397
|
+
options;
|
|
398
|
+
constructor(cwd, options) {
|
|
399
|
+
this.cwd = cwd;
|
|
400
|
+
this.options = options;
|
|
401
|
+
this.cwdPath = string.toUnixSlash(fileURLToPath(this.cwd));
|
|
402
|
+
}
|
|
403
|
+
#isAdonisJSReadyMessage(message) {
|
|
404
|
+
return message !== null && typeof message === "object" && "isAdonisJS" in message && "environment" in message && message.environment === "web";
|
|
405
|
+
}
|
|
406
|
+
#isAdonisJSRoutesMessage(message) {
|
|
407
|
+
return message !== null && typeof message === "object" && "routesFileLocation" in message;
|
|
408
|
+
}
|
|
409
|
+
async #postServerReady(message) {
|
|
410
|
+
const host = message.host === "0.0.0.0" ? "127.0.0.1" : message.host;
|
|
411
|
+
const info = {
|
|
412
|
+
host,
|
|
413
|
+
port: message.port
|
|
414
|
+
};
|
|
415
|
+
const serverUrl = `http://${host}:${message.port}`;
|
|
416
|
+
this.#shortcutsManager?.setServerUrl(serverUrl);
|
|
417
|
+
const displayMessage = this.ui.sticker().add(`Server address: ${this.ui.colors.cyan(serverUrl)}`).add(`Mode: ${this.ui.colors.cyan(this.mode)}`);
|
|
418
|
+
if (message.duration) displayMessage.add(`Ready in: ${this.ui.colors.cyan(prettyHrtime(message.duration))}`);
|
|
419
|
+
displayMessage.add(`Press ${this.ui.colors.dim("h")} to show help`);
|
|
420
|
+
try {
|
|
421
|
+
await this.#hooks.runner("devServerStarted").run(this, info, displayMessage);
|
|
422
|
+
} catch (error) {
|
|
423
|
+
this.ui.logger.error("One of the \"devServerStarted\" hooks failed");
|
|
424
|
+
this.ui.logger.fatal(error);
|
|
425
|
+
}
|
|
426
|
+
displayMessage.render();
|
|
427
|
+
}
|
|
428
|
+
#isHotHookMessage(message) {
|
|
429
|
+
return message !== null && typeof message === "object" && "type" in message && typeof message.type === "string" && message.type.startsWith("hot-hook:");
|
|
430
|
+
}
|
|
431
|
+
#clearScreen() {
|
|
432
|
+
if (this.options.clearScreen) process.stdout.write("\x1Bc");
|
|
433
|
+
}
|
|
434
|
+
#createWatcher(options) {
|
|
435
|
+
const watcher = watch({
|
|
436
|
+
usePolling: options?.poll ?? false,
|
|
437
|
+
cwd: this.cwdPath,
|
|
438
|
+
ignoreInitial: true,
|
|
439
|
+
ignored: (file, stats) => {
|
|
440
|
+
if (!stats) return false;
|
|
441
|
+
if (file.includes("inertia") && !file.includes("node_modules")) return false;
|
|
442
|
+
if (stats.isFile()) return !this.#fileSystem.shouldWatchFile(file);
|
|
443
|
+
return !this.#fileSystem.shouldWatchDirectory(file);
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
watcher.on("error", (error) => {
|
|
447
|
+
this.ui.logger.warning("file system watcher failure");
|
|
448
|
+
this.ui.logger.fatal(error);
|
|
449
|
+
this.#onError?.(error);
|
|
450
|
+
this.#watcher?.close();
|
|
451
|
+
});
|
|
452
|
+
watcher.on("ready", () => {
|
|
453
|
+
this.ui.logger.info("watching file system for changes...");
|
|
454
|
+
});
|
|
455
|
+
return watcher;
|
|
456
|
+
}
|
|
457
|
+
#handleHmrWatcherEvent(options) {
|
|
458
|
+
const relativePath = string.toUnixSlash(options.filePath);
|
|
459
|
+
const absolutePath = join(this.cwdPath, relativePath);
|
|
460
|
+
if (this.#isHttpServerAlive === false) {
|
|
461
|
+
this.#clearScreen();
|
|
462
|
+
this.ui.logger.log(`${this.ui.colors.green(options.displayLabel)} ${relativePath}`);
|
|
463
|
+
this.#restartHTTPServer();
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
if (options.action === "add") this.#hooks.runner("fileAdded").run(relativePath, absolutePath, this);
|
|
467
|
+
else if (options.action === "unlink") this.#hooks.runner("fileRemoved").run(relativePath, absolutePath, this);
|
|
468
|
+
this.#httpServer?.send({
|
|
469
|
+
type: "hot-hook:file-changed",
|
|
470
|
+
path: absolutePath,
|
|
471
|
+
action: options.action
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
#handleFileChange(relativePath, absolutePath, action, info) {
|
|
475
|
+
if ((action === "add" || action === "delete") && this.mode === "hmr") {
|
|
476
|
+
debug_default("ignoring add and delete actions in HMR mode %s", relativePath);
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (info && info.source === "hot-hook" && info.hotReloaded) {
|
|
480
|
+
debug_default("hot reloading %s, info %O", relativePath, info);
|
|
481
|
+
this.ui.logger.log(`${this.ui.colors.green("invalidated")} ${relativePath}`);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (info && !info.fullReload) {
|
|
485
|
+
debug_default("ignoring full reload", relativePath, info);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const file = this.#fileSystem.inspect(absolutePath, relativePath);
|
|
489
|
+
if (!file) return;
|
|
490
|
+
if (file.reloadServer) {
|
|
491
|
+
this.#clearScreen();
|
|
492
|
+
this.ui.logger.log(`${this.ui.colors.green(action)} ${relativePath}`);
|
|
493
|
+
this.#restartHTTPServer();
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
this.ui.logger.log(`${this.ui.colors.green(action)} ${relativePath}`);
|
|
497
|
+
}
|
|
498
|
+
#regenerateIndex(filePath, action) {
|
|
499
|
+
if (action === "add") return this.#indexGenerator.addFile(filePath);
|
|
500
|
+
return this.#indexGenerator.removeFile(filePath);
|
|
501
|
+
}
|
|
502
|
+
async #reScanRoutes(filePath) {
|
|
503
|
+
if (!this.#routesScanner) return;
|
|
504
|
+
try {
|
|
505
|
+
if (await this.#routesScanner.invalidate(filePath)) await this.#hooks.runner("routesScanned").run(this, this.#routesScanner);
|
|
506
|
+
} catch (error) {
|
|
507
|
+
this.ui.logger.error("Unable to rescan routes because of the following error");
|
|
508
|
+
this.ui.logger.fatal(error);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
#processRoutes = throttle(async (routesFileLocation) => {
|
|
512
|
+
try {
|
|
513
|
+
const scanRoutes = this.#hooks.has("routesScanning") || this.#hooks.has("routesScanned");
|
|
514
|
+
const shareRoutes = this.#hooks.has("routesCommitted");
|
|
515
|
+
if (!scanRoutes && !shareRoutes) {
|
|
516
|
+
unlink(routesFileLocation).catch(() => {});
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
const routesJSON = await readFile(routesFileLocation, "utf-8");
|
|
520
|
+
const routesList = JSON.parse(routesJSON);
|
|
521
|
+
unlink(routesFileLocation).catch(() => {});
|
|
522
|
+
if (shareRoutes) await this.#hooks.runner("routesCommitted").run(this, routesList);
|
|
523
|
+
if (scanRoutes) {
|
|
524
|
+
this.#routesScanner = new RoutesScanner(this.cwdPath, []);
|
|
525
|
+
await this.#hooks.runner("routesScanning").run(this, this.#routesScanner);
|
|
526
|
+
for (const domain of Object.keys(routesList)) await this.#routesScanner.scan(routesList[domain]);
|
|
527
|
+
await this.#hooks.runner("routesScanned").run(this, this.#routesScanner);
|
|
528
|
+
}
|
|
529
|
+
} catch (error) {
|
|
530
|
+
this.ui.logger.error("Unable to process and scan routes because of the following error");
|
|
531
|
+
this.ui.logger.fatal(error);
|
|
532
|
+
}
|
|
533
|
+
}, "processRoutes");
|
|
534
|
+
#registerServerRestartHooks() {
|
|
535
|
+
this.#hooks.add("fileAdded", (relativePath, absolutePath) => {
|
|
536
|
+
this.#regenerateIndex(absolutePath, "add");
|
|
537
|
+
this.#handleFileChange(relativePath, absolutePath, "add");
|
|
538
|
+
});
|
|
539
|
+
this.#hooks.add("fileChanged", (relativePath, absolutePath, info) => {
|
|
540
|
+
if (info.hotReloaded || !info.hotReloaded && !info.fullReload) this.#reScanRoutes(absolutePath);
|
|
541
|
+
this.#handleFileChange(relativePath, absolutePath, "update", info);
|
|
542
|
+
});
|
|
543
|
+
this.#hooks.add("fileRemoved", (relativePath, absolutePath) => {
|
|
544
|
+
this.#regenerateIndex(absolutePath, "delete");
|
|
545
|
+
this.#handleFileChange(relativePath, absolutePath, "delete");
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
async #init(mode) {
|
|
549
|
+
const tsConfig = readTsConfig(this.cwdPath);
|
|
550
|
+
if (!tsConfig) {
|
|
551
|
+
this.#onError?.(new RuntimeException("Unable to parse tsconfig file"));
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
this.#mode = mode;
|
|
555
|
+
this.#clearScreen();
|
|
556
|
+
this.ui.logger.info(`starting server in ${this.#mode} mode...`);
|
|
557
|
+
this.#indexGenerator = new IndexGenerator(this.cwdPath, this.ui.logger);
|
|
558
|
+
this.#stickyPort = String(await getPort(this.cwd));
|
|
559
|
+
this.#stickyHmrPort = String(getRandomPort({ port: 24678 }));
|
|
560
|
+
this.#fileSystem = new FileSystem(this.cwdPath, tsConfig, this.options);
|
|
561
|
+
this.ui.logger.info("loading hooks...");
|
|
562
|
+
this.#hooks = await loadHooks(this.options.hooks, [
|
|
563
|
+
"init",
|
|
564
|
+
"routesCommitted",
|
|
565
|
+
"routesScanning",
|
|
566
|
+
"routesScanned",
|
|
567
|
+
"devServerStarting",
|
|
568
|
+
"devServerStarted",
|
|
569
|
+
"fileAdded",
|
|
570
|
+
"fileChanged",
|
|
571
|
+
"fileRemoved"
|
|
572
|
+
]);
|
|
573
|
+
this.#registerServerRestartHooks();
|
|
574
|
+
this.#setupKeyboardShortcuts();
|
|
575
|
+
await this.#hooks.runner("init").run(this, this.#hooks, this.#indexGenerator);
|
|
576
|
+
this.#hooks.clear("init");
|
|
577
|
+
this.ui.logger.info("generating indexes...");
|
|
578
|
+
await this.#indexGenerator.generate();
|
|
579
|
+
return true;
|
|
580
|
+
}
|
|
581
|
+
async #startHTTPServer(port, hmrPort) {
|
|
582
|
+
await this.#hooks.runner("devServerStarting").run(this);
|
|
583
|
+
debug_default("starting http server using \"%s\" file, options %O", this.scriptFile, this.options);
|
|
584
|
+
return new Promise((resolve) => {
|
|
585
|
+
this.#httpServer = runNode(this.cwd, {
|
|
586
|
+
script: this.scriptFile,
|
|
587
|
+
env: {
|
|
588
|
+
PORT: port,
|
|
589
|
+
VITE_HMR_PORT: hmrPort,
|
|
590
|
+
DEV_MODE: "true",
|
|
591
|
+
...this.options.env
|
|
592
|
+
},
|
|
593
|
+
nodeArgs: this.options.nodeArgs,
|
|
594
|
+
reject: true,
|
|
595
|
+
scriptArgs: this.options.scriptArgs
|
|
596
|
+
});
|
|
597
|
+
this.#isHttpServerAlive = true;
|
|
598
|
+
this.#httpServer.on("message", async (message) => {
|
|
599
|
+
if (this.#isAdonisJSReadyMessage(message)) {
|
|
600
|
+
debug_default("received http server ready message %O", message);
|
|
601
|
+
await this.#postServerReady(message);
|
|
602
|
+
resolve();
|
|
603
|
+
} else if (this.#isAdonisJSRoutesMessage(message)) {
|
|
604
|
+
debug_default("received routes location from the server %O", message);
|
|
605
|
+
await this.#processRoutes(message.routesFileLocation);
|
|
606
|
+
} else if (this.#mode === "hmr" && this.#isHotHookMessage(message)) {
|
|
607
|
+
debug_default("received hot-hook message %O", message);
|
|
608
|
+
if (message.type === "hot-hook:full-reload") {
|
|
609
|
+
const absolutePath = message.path ? string.toUnixSlash(message.path) : "";
|
|
610
|
+
const relativePath = relative(this.cwdPath, absolutePath);
|
|
611
|
+
this.#hooks.runner("fileChanged").run(relativePath, absolutePath, DevServer.#HOT_HOOK_FULL_RELOAD_INFO, this);
|
|
612
|
+
} else if (message.type === "hot-hook:invalidated") {
|
|
613
|
+
const absolutePath = message.paths[0] ? string.toUnixSlash(message.paths[0]) : "";
|
|
614
|
+
const relativePath = relative(this.cwdPath, absolutePath);
|
|
615
|
+
this.#hooks.runner("fileChanged").run(relativePath, absolutePath, DevServer.#HOT_HOOK_INVALIDATED_INFO, this);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
this.#httpServer.then((result) => {
|
|
620
|
+
this.#isHttpServerAlive = false;
|
|
621
|
+
if (!this.#watcher) this.#onClose?.(result.exitCode);
|
|
622
|
+
else this.ui.logger.info("Underlying HTTP server closed. Still watching for changes");
|
|
623
|
+
}).catch((error) => {
|
|
624
|
+
this.#isHttpServerAlive = false;
|
|
625
|
+
if (!this.#watcher) this.#onError?.(error);
|
|
626
|
+
else this.ui.logger.info("Underlying HTTP server died. Still watching for changes");
|
|
627
|
+
}).finally(() => {
|
|
628
|
+
resolve();
|
|
629
|
+
});
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
onClose(callback) {
|
|
633
|
+
this.#onClose = callback;
|
|
634
|
+
return this;
|
|
635
|
+
}
|
|
636
|
+
onError(callback) {
|
|
637
|
+
this.#onError = callback;
|
|
638
|
+
return this;
|
|
639
|
+
}
|
|
640
|
+
async close() {
|
|
641
|
+
this.#cleanupKeyboardShortcuts();
|
|
642
|
+
await this.#watcher?.close();
|
|
643
|
+
if (this.#httpServer) {
|
|
644
|
+
this.#httpServer.removeAllListeners();
|
|
645
|
+
this.#httpServer.kill("SIGKILL");
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
async start() {
|
|
649
|
+
if (!await this.#init(this.options.hmr ? "hmr" : "static")) return;
|
|
650
|
+
if (this.#mode === "hmr") {
|
|
651
|
+
this.options.nodeArgs.push("--import=hot-hook/register");
|
|
652
|
+
this.options.env = {
|
|
653
|
+
...this.options.env,
|
|
654
|
+
HOT_HOOK_WATCH: "false"
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
this.ui.logger.info("starting HTTP server...");
|
|
658
|
+
await this.#startHTTPServer(this.#stickyPort, this.#stickyHmrPort);
|
|
659
|
+
if (this.#mode !== "hmr") return;
|
|
660
|
+
this.#watcher = this.#createWatcher();
|
|
661
|
+
this.#watcher.on("add", (filePath) => {
|
|
662
|
+
this.#handleHmrWatcherEvent({
|
|
663
|
+
filePath,
|
|
664
|
+
action: "add",
|
|
665
|
+
displayLabel: "add"
|
|
666
|
+
});
|
|
667
|
+
});
|
|
668
|
+
this.#watcher.on("change", (filePath) => {
|
|
669
|
+
this.#handleHmrWatcherEvent({
|
|
670
|
+
filePath,
|
|
671
|
+
action: "change",
|
|
672
|
+
displayLabel: "update"
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
this.#watcher.on("unlink", (filePath) => {
|
|
676
|
+
this.#handleHmrWatcherEvent({
|
|
677
|
+
filePath,
|
|
678
|
+
action: "unlink",
|
|
679
|
+
displayLabel: "delete"
|
|
680
|
+
});
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
async startAndWatch(options) {
|
|
684
|
+
if (!await this.#init("watch")) return;
|
|
685
|
+
this.ui.logger.info("starting HTTP server...");
|
|
686
|
+
await this.#startHTTPServer(this.#stickyPort, this.#stickyHmrPort);
|
|
687
|
+
this.#watcher = this.#createWatcher({ poll: options?.poll });
|
|
688
|
+
this.#watcher.on("add", (filePath) => {
|
|
689
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
690
|
+
const absolutePath = join(this.cwdPath, relativePath);
|
|
691
|
+
this.#hooks.runner("fileAdded").run(relativePath, absolutePath, this);
|
|
692
|
+
});
|
|
693
|
+
this.#watcher.on("change", (filePath) => {
|
|
694
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
695
|
+
const absolutePath = join(this.cwdPath, relativePath);
|
|
696
|
+
this.#hooks.runner("fileChanged").run(relativePath, absolutePath, DevServer.#WATCHER_INFO, this);
|
|
697
|
+
});
|
|
698
|
+
this.#watcher.on("unlink", (filePath) => {
|
|
699
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
700
|
+
const absolutePath = join(this.cwdPath, relativePath);
|
|
701
|
+
this.#hooks.runner("fileRemoved").run(relativePath, absolutePath, this);
|
|
702
|
+
});
|
|
703
|
+
}
|
|
1042
704
|
};
|
|
1043
|
-
|
|
1044
|
-
// src/test_runner.ts
|
|
1045
|
-
import { cliui as cliui3 } from "@poppinss/cliui";
|
|
1046
|
-
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1047
|
-
import string4 from "@poppinss/utils/string";
|
|
1048
705
|
var TestRunner = class {
|
|
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
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
this.#clearScreen();
|
|
1290
|
-
this.ui.logger.info("booting application to run tests...");
|
|
1291
|
-
await this.#runTests(this.#stickyPort);
|
|
1292
|
-
this.#watcher = watch({
|
|
1293
|
-
usePolling: options?.poll ?? false,
|
|
1294
|
-
cwd: fileURLToPath5(this.cwd),
|
|
1295
|
-
ignoreInitial: true,
|
|
1296
|
-
ignored: (file, stats) => {
|
|
1297
|
-
if (!stats) {
|
|
1298
|
-
return false;
|
|
1299
|
-
}
|
|
1300
|
-
if (stats.isFile()) {
|
|
1301
|
-
return !this.#fileSystem.shouldWatchFile(file);
|
|
1302
|
-
}
|
|
1303
|
-
return !this.#fileSystem.shouldWatchDirectory(file);
|
|
1304
|
-
}
|
|
1305
|
-
});
|
|
1306
|
-
this.#watcher.on("ready", () => {
|
|
1307
|
-
this.ui.logger.info("watching file system for changes...");
|
|
1308
|
-
});
|
|
1309
|
-
this.#watcher.on("error", (error) => {
|
|
1310
|
-
this.ui.logger.warning("file system watcher failure");
|
|
1311
|
-
this.ui.logger.fatal(error);
|
|
1312
|
-
this.#onError?.(error);
|
|
1313
|
-
this.#watcher?.close();
|
|
1314
|
-
});
|
|
1315
|
-
this.#watcher.on(
|
|
1316
|
-
"add",
|
|
1317
|
-
(filePath) => this.#hooks.runner("fileAdded").run(string4.toUnixSlash(filePath), this)
|
|
1318
|
-
);
|
|
1319
|
-
this.#watcher.on(
|
|
1320
|
-
"change",
|
|
1321
|
-
(filePath) => this.#hooks.runner("fileChanged").run(
|
|
1322
|
-
string4.toUnixSlash(filePath),
|
|
1323
|
-
{
|
|
1324
|
-
source: "watcher",
|
|
1325
|
-
fullReload: true,
|
|
1326
|
-
hotReloaded: false
|
|
1327
|
-
},
|
|
1328
|
-
this
|
|
1329
|
-
)
|
|
1330
|
-
);
|
|
1331
|
-
this.#watcher.on(
|
|
1332
|
-
"unlink",
|
|
1333
|
-
(filePath) => this.#hooks.runner("fileRemoved").run(string4.toUnixSlash(filePath), this)
|
|
1334
|
-
);
|
|
1335
|
-
}
|
|
1336
|
-
};
|
|
1337
|
-
export {
|
|
1338
|
-
Bundler,
|
|
1339
|
-
DevServer,
|
|
1340
|
-
TestRunner
|
|
706
|
+
#onError;
|
|
707
|
+
#onClose;
|
|
708
|
+
#stickyPort;
|
|
709
|
+
#stickyHmrPort;
|
|
710
|
+
#watcher;
|
|
711
|
+
#testsProcess;
|
|
712
|
+
#fileSystem;
|
|
713
|
+
#hooks;
|
|
714
|
+
#indexGenerator;
|
|
715
|
+
ui = cliui();
|
|
716
|
+
#reRunTests = throttle(async (filters) => {
|
|
717
|
+
if (this.#testsProcess) {
|
|
718
|
+
this.#testsProcess.removeAllListeners();
|
|
719
|
+
this.#testsProcess.kill("SIGKILL");
|
|
720
|
+
}
|
|
721
|
+
await this.#runTests(this.#stickyPort, this.#stickyHmrPort, filters);
|
|
722
|
+
}, "reRunTests");
|
|
723
|
+
scriptFile = "bin/test.ts";
|
|
724
|
+
cwd;
|
|
725
|
+
cwdPath;
|
|
726
|
+
options;
|
|
727
|
+
constructor(cwd, options) {
|
|
728
|
+
this.cwd = cwd;
|
|
729
|
+
this.options = options;
|
|
730
|
+
this.cwdPath = string.toUnixSlash(fileURLToPath(this.cwd));
|
|
731
|
+
}
|
|
732
|
+
#convertOptionsToArgs() {
|
|
733
|
+
const args = [];
|
|
734
|
+
if (this.options.reporters) {
|
|
735
|
+
args.push("--reporters");
|
|
736
|
+
args.push(this.options.reporters.join(","));
|
|
737
|
+
}
|
|
738
|
+
if (this.options.timeout !== void 0) {
|
|
739
|
+
args.push("--timeout");
|
|
740
|
+
args.push(String(this.options.timeout));
|
|
741
|
+
}
|
|
742
|
+
if (this.options.failed) args.push("--failed");
|
|
743
|
+
if (this.options.retries !== void 0) {
|
|
744
|
+
args.push("--retries");
|
|
745
|
+
args.push(String(this.options.retries));
|
|
746
|
+
}
|
|
747
|
+
return args;
|
|
748
|
+
}
|
|
749
|
+
#convertFiltersToArgs(filters) {
|
|
750
|
+
const args = [];
|
|
751
|
+
if (filters.suites) args.push(...filters.suites);
|
|
752
|
+
if (filters.files) {
|
|
753
|
+
args.push("--files");
|
|
754
|
+
args.push(filters.files.join(","));
|
|
755
|
+
}
|
|
756
|
+
if (filters.groups) {
|
|
757
|
+
args.push("--groups");
|
|
758
|
+
args.push(filters.groups.join(","));
|
|
759
|
+
}
|
|
760
|
+
if (filters.tags) {
|
|
761
|
+
args.push("--tags");
|
|
762
|
+
args.push(filters.tags.join(","));
|
|
763
|
+
}
|
|
764
|
+
if (filters.tests) {
|
|
765
|
+
args.push("--tests");
|
|
766
|
+
args.push(filters.tests.join(","));
|
|
767
|
+
}
|
|
768
|
+
return args;
|
|
769
|
+
}
|
|
770
|
+
#clearScreen() {
|
|
771
|
+
if (this.options.clearScreen) process.stdout.write("\x1Bc");
|
|
772
|
+
}
|
|
773
|
+
async #runTests(port, hmrPort, filters) {
|
|
774
|
+
await this.#hooks.runner("testsStarting").run(this);
|
|
775
|
+
debug_default("running tests using \"%s\" file, options %O", this.scriptFile, this.options);
|
|
776
|
+
return new Promise(async (resolve) => {
|
|
777
|
+
const mergedFilters = {
|
|
778
|
+
...this.options.filters,
|
|
779
|
+
...filters
|
|
780
|
+
};
|
|
781
|
+
const scriptArgs = [
|
|
782
|
+
...this.#convertOptionsToArgs(),
|
|
783
|
+
...this.options.scriptArgs,
|
|
784
|
+
...this.#convertFiltersToArgs(mergedFilters)
|
|
785
|
+
];
|
|
786
|
+
this.#testsProcess = runNode(this.cwd, {
|
|
787
|
+
script: this.scriptFile,
|
|
788
|
+
reject: true,
|
|
789
|
+
env: {
|
|
790
|
+
PORT: port,
|
|
791
|
+
VITE_HMR_PORT: hmrPort,
|
|
792
|
+
...this.options.env
|
|
793
|
+
},
|
|
794
|
+
nodeArgs: this.options.nodeArgs,
|
|
795
|
+
scriptArgs
|
|
796
|
+
});
|
|
797
|
+
this.#testsProcess.then((result) => {
|
|
798
|
+
this.#hooks.runner("testsFinished").run(this).catch((error) => {
|
|
799
|
+
this.ui.logger.error("One of the \"testsFinished\" hooks failed");
|
|
800
|
+
this.ui.logger.fatal(error);
|
|
801
|
+
}).finally(() => {
|
|
802
|
+
if (!this.#watcher) {
|
|
803
|
+
this.#onClose?.(result.exitCode);
|
|
804
|
+
this.close();
|
|
805
|
+
}
|
|
806
|
+
});
|
|
807
|
+
}).catch((error) => {
|
|
808
|
+
if (!this.#watcher) {
|
|
809
|
+
this.#onError?.(error);
|
|
810
|
+
this.close();
|
|
811
|
+
} else this.ui.logger.info("Underlying HTTP server died. Still watching for changes");
|
|
812
|
+
}).finally(() => resolve());
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
#handleFileChange(relativePath, absolutePath, action) {
|
|
816
|
+
const file = this.#fileSystem.inspect(absolutePath, relativePath);
|
|
817
|
+
if (!file) return;
|
|
818
|
+
this.#clearScreen();
|
|
819
|
+
this.ui.logger.log(`${this.ui.colors.green(action)} ${relativePath}`);
|
|
820
|
+
if (file.fileType === "test") this.#reRunTests({ files: [relativePath] });
|
|
821
|
+
else this.#reRunTests();
|
|
822
|
+
}
|
|
823
|
+
#regenerateIndex(filePath, action) {
|
|
824
|
+
if (action === "add") return this.#indexGenerator.addFile(filePath);
|
|
825
|
+
return this.#indexGenerator.removeFile(filePath);
|
|
826
|
+
}
|
|
827
|
+
#registerServerRestartHooks() {
|
|
828
|
+
this.#hooks.add("fileAdded", (relativePath, absolutePath) => {
|
|
829
|
+
this.#regenerateIndex(absolutePath, "add");
|
|
830
|
+
this.#handleFileChange(relativePath, absolutePath, "add");
|
|
831
|
+
});
|
|
832
|
+
this.#hooks.add("fileChanged", (relativePath, absolutePath) => {
|
|
833
|
+
this.#regenerateIndex(absolutePath, "add");
|
|
834
|
+
this.#handleFileChange(relativePath, absolutePath, "update");
|
|
835
|
+
});
|
|
836
|
+
this.#hooks.add("fileRemoved", (relativePath, absolutePath) => {
|
|
837
|
+
this.#regenerateIndex(absolutePath, "delete");
|
|
838
|
+
this.#handleFileChange(relativePath, absolutePath, "delete");
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
onClose(callback) {
|
|
842
|
+
this.#onClose = callback;
|
|
843
|
+
return this;
|
|
844
|
+
}
|
|
845
|
+
onError(callback) {
|
|
846
|
+
this.#onError = callback;
|
|
847
|
+
return this;
|
|
848
|
+
}
|
|
849
|
+
async close() {
|
|
850
|
+
await this.#watcher?.close();
|
|
851
|
+
if (this.#testsProcess) {
|
|
852
|
+
this.#testsProcess.removeAllListeners();
|
|
853
|
+
this.#testsProcess.kill("SIGKILL");
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
async run() {
|
|
857
|
+
this.#stickyPort = String(await getPort(this.cwd));
|
|
858
|
+
this.#stickyHmrPort = String(getRandomPort({ port: 24678 }));
|
|
859
|
+
this.#indexGenerator = new IndexGenerator(this.cwdPath, this.ui.logger);
|
|
860
|
+
this.#clearScreen();
|
|
861
|
+
this.ui.logger.info("loading hooks...");
|
|
862
|
+
this.#hooks = await loadHooks(this.options.hooks, [
|
|
863
|
+
"init",
|
|
864
|
+
"testsStarting",
|
|
865
|
+
"testsFinished"
|
|
866
|
+
]);
|
|
867
|
+
await this.#hooks.runner("init").run(this, this.#hooks, this.#indexGenerator);
|
|
868
|
+
this.#hooks.clear("init");
|
|
869
|
+
this.ui.logger.info("generating indexes...");
|
|
870
|
+
await this.#indexGenerator.generate();
|
|
871
|
+
this.ui.logger.info("booting application to run tests...");
|
|
872
|
+
await this.#runTests(this.#stickyPort, this.#stickyHmrPort);
|
|
873
|
+
}
|
|
874
|
+
async runAndWatch(options) {
|
|
875
|
+
const tsConfig = readTsConfig(this.cwdPath);
|
|
876
|
+
if (!tsConfig) {
|
|
877
|
+
this.#onError?.(new RuntimeException("Unable to parse tsconfig file"));
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
this.#stickyPort = String(await getPort(this.cwd));
|
|
881
|
+
this.#stickyHmrPort = String(getRandomPort({ port: 24678 }));
|
|
882
|
+
this.#indexGenerator = new IndexGenerator(this.cwdPath, this.ui.logger);
|
|
883
|
+
this.#fileSystem = new FileSystem(this.cwdPath, tsConfig, {
|
|
884
|
+
...this.options,
|
|
885
|
+
suites: this.options.suites?.filter((suite) => {
|
|
886
|
+
if (this.options.filters.suites) return this.options.filters.suites.includes(suite.name);
|
|
887
|
+
return true;
|
|
888
|
+
})
|
|
889
|
+
});
|
|
890
|
+
this.#clearScreen();
|
|
891
|
+
this.ui.logger.info("loading hooks...");
|
|
892
|
+
this.#hooks = await loadHooks(this.options.hooks, [
|
|
893
|
+
"init",
|
|
894
|
+
"testsStarting",
|
|
895
|
+
"testsFinished",
|
|
896
|
+
"fileAdded",
|
|
897
|
+
"fileChanged",
|
|
898
|
+
"fileRemoved"
|
|
899
|
+
]);
|
|
900
|
+
this.#registerServerRestartHooks();
|
|
901
|
+
await this.#hooks.runner("init").run(this, this.#hooks, this.#indexGenerator);
|
|
902
|
+
this.#hooks.clear("init");
|
|
903
|
+
this.ui.logger.info("generating indexes...");
|
|
904
|
+
await this.#indexGenerator.generate();
|
|
905
|
+
this.ui.logger.info("booting application to run tests...");
|
|
906
|
+
await this.#runTests(this.#stickyPort, this.#stickyHmrPort);
|
|
907
|
+
this.#watcher = watch({
|
|
908
|
+
usePolling: options?.poll ?? false,
|
|
909
|
+
cwd: this.cwdPath,
|
|
910
|
+
ignoreInitial: true,
|
|
911
|
+
ignored: (file, stats) => {
|
|
912
|
+
if (!stats) return false;
|
|
913
|
+
if (stats.isFile()) return !this.#fileSystem.shouldWatchFile(file);
|
|
914
|
+
return !this.#fileSystem.shouldWatchDirectory(file);
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
this.#watcher.on("ready", () => {
|
|
918
|
+
this.ui.logger.info("watching file system for changes...");
|
|
919
|
+
});
|
|
920
|
+
this.#watcher.on("error", (error) => {
|
|
921
|
+
this.ui.logger.warning("file system watcher failure");
|
|
922
|
+
this.ui.logger.fatal(error);
|
|
923
|
+
this.#onError?.(error);
|
|
924
|
+
this.#watcher?.close();
|
|
925
|
+
});
|
|
926
|
+
this.#watcher.on("add", (filePath) => {
|
|
927
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
928
|
+
const absolutePath = join(this.cwdPath, filePath);
|
|
929
|
+
this.#hooks.runner("fileAdded").run(relativePath, absolutePath, this);
|
|
930
|
+
});
|
|
931
|
+
this.#watcher.on("change", (filePath) => {
|
|
932
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
933
|
+
const absolutePath = join(this.cwdPath, filePath);
|
|
934
|
+
this.#hooks.runner("fileChanged").run(relativePath, absolutePath, {
|
|
935
|
+
source: "watcher",
|
|
936
|
+
fullReload: true,
|
|
937
|
+
hotReloaded: false
|
|
938
|
+
}, this);
|
|
939
|
+
});
|
|
940
|
+
this.#watcher.on("unlink", (filePath) => {
|
|
941
|
+
const relativePath = string.toUnixSlash(filePath);
|
|
942
|
+
const absolutePath = join(this.cwdPath, filePath);
|
|
943
|
+
this.#hooks.runner("fileRemoved").run(relativePath, absolutePath, this);
|
|
944
|
+
});
|
|
945
|
+
}
|
|
1341
946
|
};
|
|
947
|
+
export { Bundler, CodemodException, DevServer, FileBuffer, SUPPORTED_PACKAGE_MANAGERS, TestRunner, VirtualFileSystem };
|