@adonisjs/assembler 6.1.3-9 → 7.0.0-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +418 -11
- package/build/index.js +999 -11
- package/build/index.js.map +1 -0
- package/build/src/bundler.d.ts +3 -1
- package/build/src/code_transformer/main.d.ts +48 -0
- package/build/src/code_transformer/main.js +478 -0
- package/build/src/code_transformer/main.js.map +1 -0
- package/build/src/code_transformer/rc_file_transformer.d.ts +43 -0
- package/build/src/debug.d.ts +3 -0
- package/build/src/dev_server.d.ts +2 -2
- package/build/src/helpers.d.ts +7 -6
- package/build/src/test_runner.d.ts +8 -7
- package/build/src/types.d.ts +157 -20
- package/package.json +72 -46
- package/build/src/assets_dev_server.js +0 -158
- package/build/src/bundler.js +0 -223
- package/build/src/dev_server.js +0 -253
- package/build/src/helpers.js +0 -142
- package/build/src/test_runner.js +0 -287
- package/build/src/types.js +0 -9
package/build/index.js
CHANGED
|
@@ -1,11 +1,999 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
// src/bundler.ts
|
|
2
|
+
import slash from "slash";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import { relative as relative2 } from "node:path";
|
|
5
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
6
|
+
import { cliui } from "@poppinss/cliui";
|
|
7
|
+
import { detectPackageManager } from "@antfu/install-pkg";
|
|
8
|
+
|
|
9
|
+
// src/helpers.ts
|
|
10
|
+
import { isJunk } from "junk";
|
|
11
|
+
import fastGlob from "fast-glob";
|
|
12
|
+
import getRandomPort from "get-port";
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
import { execaNode, execa } from "execa";
|
|
16
|
+
import { copyFile, mkdir } from "node:fs/promises";
|
|
17
|
+
import { EnvLoader, EnvParser } from "@adonisjs/env";
|
|
18
|
+
import { ConfigParser, Watcher } from "@poppinss/chokidar-ts";
|
|
19
|
+
import { basename, dirname, isAbsolute, join, relative } from "node:path";
|
|
20
|
+
|
|
21
|
+
// src/debug.ts
|
|
22
|
+
import { debuglog } from "node:util";
|
|
23
|
+
var debug_default = debuglog("adonisjs:assembler");
|
|
24
|
+
|
|
25
|
+
// src/helpers.ts
|
|
26
|
+
var DEFAULT_NODE_ARGS = [
|
|
27
|
+
// Use ts-node/esm loader. The project must install it
|
|
28
|
+
"--loader=ts-node/esm",
|
|
29
|
+
// Disable annoying warnings
|
|
30
|
+
"--no-warnings",
|
|
31
|
+
// Enable expiremental meta resolve for cases where someone uses magic import string
|
|
32
|
+
"--experimental-import-meta-resolve",
|
|
33
|
+
// Enable source maps, since TSNode source maps are broken
|
|
34
|
+
"--enable-source-maps"
|
|
35
|
+
];
|
|
36
|
+
function parseConfig(cwd, ts) {
|
|
37
|
+
const { config, error } = new ConfigParser(cwd, "tsconfig.json", ts).parse();
|
|
38
|
+
if (error) {
|
|
39
|
+
const compilerHost = ts.createCompilerHost({});
|
|
40
|
+
console.log(ts.formatDiagnosticsWithColorAndContext([error], compilerHost));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (config.errors.length) {
|
|
44
|
+
const compilerHost = ts.createCompilerHost({});
|
|
45
|
+
console.log(ts.formatDiagnosticsWithColorAndContext(config.errors, compilerHost));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
return config;
|
|
49
|
+
}
|
|
50
|
+
function runNode(cwd, options) {
|
|
51
|
+
const childProcess = execaNode(options.script, options.scriptArgs, {
|
|
52
|
+
nodeOptions: DEFAULT_NODE_ARGS.concat(options.nodeArgs),
|
|
53
|
+
preferLocal: true,
|
|
54
|
+
windowsHide: false,
|
|
55
|
+
localDir: cwd,
|
|
56
|
+
cwd,
|
|
57
|
+
buffer: false,
|
|
58
|
+
stdio: options.stdio || "inherit",
|
|
59
|
+
env: {
|
|
60
|
+
...options.stdio === "pipe" ? { FORCE_COLOR: "true" } : {},
|
|
61
|
+
...options.env
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
return childProcess;
|
|
65
|
+
}
|
|
66
|
+
function run(cwd, options) {
|
|
67
|
+
const childProcess = execa(options.script, options.scriptArgs, {
|
|
68
|
+
preferLocal: true,
|
|
69
|
+
windowsHide: false,
|
|
70
|
+
localDir: cwd,
|
|
71
|
+
cwd,
|
|
72
|
+
buffer: false,
|
|
73
|
+
stdio: options.stdio || "inherit",
|
|
74
|
+
env: {
|
|
75
|
+
...options.stdio === "pipe" ? { FORCE_COLOR: "true" } : {},
|
|
76
|
+
...options.env
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
return childProcess;
|
|
80
|
+
}
|
|
81
|
+
function watch(cwd, ts, options) {
|
|
82
|
+
const config = parseConfig(cwd, ts);
|
|
83
|
+
if (!config) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const watcher = new Watcher(typeof cwd === "string" ? cwd : fileURLToPath(cwd), config);
|
|
87
|
+
const chokidar = watcher.watch(["."], { usePolling: options.poll });
|
|
88
|
+
return { watcher, chokidar };
|
|
89
|
+
}
|
|
90
|
+
function isDotEnvFile(filePath) {
|
|
91
|
+
if (filePath === ".env") {
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
return filePath.includes(".env.");
|
|
95
|
+
}
|
|
96
|
+
async function getPort(cwd) {
|
|
97
|
+
if (process.env.PORT) {
|
|
98
|
+
return getRandomPort({ port: Number(process.env.PORT) });
|
|
99
|
+
}
|
|
100
|
+
const files = await new EnvLoader(cwd).load();
|
|
101
|
+
for (let file of files) {
|
|
102
|
+
const envVariables = new EnvParser(file.contents).parse();
|
|
103
|
+
if (envVariables.PORT) {
|
|
104
|
+
return getRandomPort({ port: Number(envVariables.PORT) });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return getRandomPort({ port: 3333 });
|
|
108
|
+
}
|
|
109
|
+
async function copyFiles(files, cwd, outDir) {
|
|
110
|
+
const { paths, patterns } = files.reduce(
|
|
111
|
+
(result, file) => {
|
|
112
|
+
if (fastGlob.isDynamicPattern(file)) {
|
|
113
|
+
result.patterns.push(file);
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
if (existsSync(join(cwd, file))) {
|
|
117
|
+
result.paths.push(file);
|
|
118
|
+
}
|
|
119
|
+
return result;
|
|
120
|
+
},
|
|
121
|
+
{ patterns: [], paths: [] }
|
|
122
|
+
);
|
|
123
|
+
debug_default("copyFiles inputs: %O, paths: %O, patterns: %O", files, paths, patterns);
|
|
124
|
+
const filePaths = paths.concat(await fastGlob(patterns, { cwd, dot: true })).filter((file) => {
|
|
125
|
+
return !isJunk(basename(file));
|
|
126
|
+
});
|
|
127
|
+
debug_default('copying files %O to destination "%s"', filePaths, outDir);
|
|
128
|
+
const copyPromises = filePaths.map(async (file) => {
|
|
129
|
+
const src = isAbsolute(file) ? file : join(cwd, file);
|
|
130
|
+
const dest = join(outDir, relative(cwd, src));
|
|
131
|
+
await mkdir(dirname(dest), { recursive: true });
|
|
132
|
+
return copyFile(src, dest);
|
|
133
|
+
});
|
|
134
|
+
return await Promise.all(copyPromises);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/bundler.ts
|
|
138
|
+
var SUPPORT_PACKAGE_MANAGERS = {
|
|
139
|
+
npm: {
|
|
140
|
+
lockFile: "package-lock.json",
|
|
141
|
+
installCommand: 'npm ci --omit="dev"'
|
|
142
|
+
},
|
|
143
|
+
yarn: {
|
|
144
|
+
lockFile: "yarn.lock",
|
|
145
|
+
installCommand: "yarn install --production"
|
|
146
|
+
},
|
|
147
|
+
pnpm: {
|
|
148
|
+
lockFile: "pnpm-lock.yaml",
|
|
149
|
+
installCommand: "pnpm i --prod"
|
|
150
|
+
},
|
|
151
|
+
bun: {
|
|
152
|
+
lockFile: "bun.lockb",
|
|
153
|
+
installCommand: "bun install --production"
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
var ui = cliui();
|
|
157
|
+
var Bundler = class {
|
|
158
|
+
#cwd;
|
|
159
|
+
#cwdPath;
|
|
160
|
+
#ts;
|
|
161
|
+
#logger = ui.logger;
|
|
162
|
+
#options;
|
|
163
|
+
/**
|
|
164
|
+
* Getting reference to colors library from logger
|
|
165
|
+
*/
|
|
166
|
+
get #colors() {
|
|
167
|
+
return this.#logger.getColors();
|
|
168
|
+
}
|
|
169
|
+
constructor(cwd, ts, options) {
|
|
170
|
+
this.#cwd = cwd;
|
|
171
|
+
this.#cwdPath = fileURLToPath2(this.#cwd);
|
|
172
|
+
this.#ts = ts;
|
|
173
|
+
this.#options = options;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Returns the relative unix path for an absolute
|
|
177
|
+
* file path
|
|
178
|
+
*/
|
|
179
|
+
#getRelativeName(filePath) {
|
|
180
|
+
return slash(relative2(this.#cwdPath, filePath));
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Cleans up the build directory
|
|
184
|
+
*/
|
|
185
|
+
async #cleanupBuildDirectory(outDir) {
|
|
186
|
+
await fs.rm(outDir, { recursive: true, force: true, maxRetries: 5 });
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Runs assets bundler command to build assets
|
|
190
|
+
*/
|
|
191
|
+
async #buildAssets() {
|
|
192
|
+
const assetsBundler = this.#options.assets;
|
|
193
|
+
if (!assetsBundler?.enabled) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
this.#logger.info("compiling frontend assets", { suffix: assetsBundler.cmd });
|
|
198
|
+
await run(this.#cwd, {
|
|
199
|
+
stdio: "inherit",
|
|
200
|
+
script: assetsBundler.cmd,
|
|
201
|
+
scriptArgs: assetsBundler.args
|
|
202
|
+
});
|
|
203
|
+
return true;
|
|
204
|
+
} catch {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Runs tsc command to build the source.
|
|
210
|
+
*/
|
|
211
|
+
async #runTsc(outDir) {
|
|
212
|
+
try {
|
|
213
|
+
await run(this.#cwd, {
|
|
214
|
+
stdio: "inherit",
|
|
215
|
+
script: "tsc",
|
|
216
|
+
scriptArgs: ["--outDir", outDir]
|
|
217
|
+
});
|
|
218
|
+
return true;
|
|
219
|
+
} catch {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Copy meta files to the output directory
|
|
225
|
+
*/
|
|
226
|
+
async #copyMetaFiles(outDir, additionalFilesToCopy) {
|
|
227
|
+
const metaFiles = (this.#options.metaFiles || []).map((file) => file.pattern).concat(additionalFilesToCopy);
|
|
228
|
+
await copyFiles(metaFiles, this.#cwdPath, outDir);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Detect the package manager used by the project
|
|
232
|
+
* and return the lockfile name and install command
|
|
233
|
+
* related to it.
|
|
234
|
+
*/
|
|
235
|
+
async #getPackageManager(client) {
|
|
236
|
+
let pkgManager = client;
|
|
237
|
+
if (!pkgManager) {
|
|
238
|
+
pkgManager = await detectPackageManager(this.#cwdPath);
|
|
239
|
+
}
|
|
240
|
+
if (!pkgManager) {
|
|
241
|
+
pkgManager = "npm";
|
|
242
|
+
}
|
|
243
|
+
if (!Object.keys(SUPPORT_PACKAGE_MANAGERS).includes(pkgManager)) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
return SUPPORT_PACKAGE_MANAGERS[pkgManager];
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Set a custom CLI UI logger
|
|
250
|
+
*/
|
|
251
|
+
setLogger(logger) {
|
|
252
|
+
this.#logger = logger;
|
|
253
|
+
return this;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Bundles the application to be run in production
|
|
257
|
+
*/
|
|
258
|
+
async bundle(stopOnError = true, client) {
|
|
259
|
+
const config = parseConfig(this.#cwd, this.#ts);
|
|
260
|
+
if (!config) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
const outDir = config.options.outDir || fileURLToPath2(new URL("build/", this.#cwd));
|
|
264
|
+
this.#logger.info("cleaning up output directory", { suffix: this.#getRelativeName(outDir) });
|
|
265
|
+
await this.#cleanupBuildDirectory(outDir);
|
|
266
|
+
if (!await this.#buildAssets()) {
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
this.#logger.info("compiling typescript source", { suffix: "tsc" });
|
|
270
|
+
const buildCompleted = await this.#runTsc(outDir);
|
|
271
|
+
await copyFiles(["ace.js"], this.#cwdPath, outDir);
|
|
272
|
+
if (!buildCompleted && stopOnError) {
|
|
273
|
+
await this.#cleanupBuildDirectory(outDir);
|
|
274
|
+
const instructions = ui.sticker().fullScreen().drawBorder((borderChar, colors) => colors.red(borderChar));
|
|
275
|
+
instructions.add(
|
|
276
|
+
this.#colors.red("Cannot complete the build process as there are TypeScript errors.")
|
|
277
|
+
);
|
|
278
|
+
instructions.add(
|
|
279
|
+
this.#colors.red(
|
|
280
|
+
'Use "--ignore-ts-errors" flag to ignore TypeScript errors and continue the build.'
|
|
281
|
+
)
|
|
282
|
+
);
|
|
283
|
+
this.#logger.logError(instructions.prepare());
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
const pkgManager = await this.#getPackageManager(client);
|
|
287
|
+
const pkgFiles = pkgManager ? ["package.json", pkgManager.lockFile] : ["package.json"];
|
|
288
|
+
this.#logger.info("copying meta files to the output directory");
|
|
289
|
+
await this.#copyMetaFiles(outDir, pkgFiles);
|
|
290
|
+
this.#logger.success("build completed");
|
|
291
|
+
this.#logger.log("");
|
|
292
|
+
ui.instructions().useRenderer(this.#logger.getRenderer()).heading("Run the following commands to start the server in production").add(this.#colors.cyan(`cd ${this.#getRelativeName(outDir)}`)).add(
|
|
293
|
+
this.#colors.cyan(
|
|
294
|
+
pkgManager ? pkgManager.installCommand : "Install production dependencies"
|
|
295
|
+
)
|
|
296
|
+
).add(this.#colors.cyan("node bin/server.js")).render();
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
// src/dev_server.ts
|
|
302
|
+
import picomatch from "picomatch";
|
|
303
|
+
import prettyHrtime from "pretty-hrtime";
|
|
304
|
+
import { cliui as cliui3 } from "@poppinss/cliui";
|
|
305
|
+
|
|
306
|
+
// src/assets_dev_server.ts
|
|
307
|
+
import { cliui as cliui2 } from "@poppinss/cliui";
|
|
308
|
+
var ui2 = cliui2();
|
|
309
|
+
var AssetsDevServer = class {
|
|
310
|
+
#cwd;
|
|
311
|
+
#logger = ui2.logger;
|
|
312
|
+
#options;
|
|
313
|
+
#devServer;
|
|
314
|
+
/**
|
|
315
|
+
* Getting reference to colors library from logger
|
|
316
|
+
*/
|
|
317
|
+
get #colors() {
|
|
318
|
+
return this.#logger.getColors();
|
|
319
|
+
}
|
|
320
|
+
constructor(cwd, options) {
|
|
321
|
+
this.#cwd = cwd;
|
|
322
|
+
this.#options = options;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Logs messages from vite dev server stdout and stderr
|
|
326
|
+
*/
|
|
327
|
+
#logViteDevServerMessage(data) {
|
|
328
|
+
const dataString = data.toString();
|
|
329
|
+
const lines = dataString.split("\n");
|
|
330
|
+
if (dataString.includes("Local") && dataString.includes("Network")) {
|
|
331
|
+
const sticker = ui2.sticker().useColors(this.#colors).useRenderer(this.#logger.getRenderer());
|
|
332
|
+
lines.forEach((line) => {
|
|
333
|
+
if (line.trim()) {
|
|
334
|
+
sticker.add(line);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
sticker.render();
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (dataString.includes("ready in")) {
|
|
341
|
+
console.log("");
|
|
342
|
+
console.log(dataString.trim());
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
lines.forEach((line) => {
|
|
346
|
+
if (line.trim()) {
|
|
347
|
+
console.log(line);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Logs messages from assets dev server stdout and stderr
|
|
353
|
+
*/
|
|
354
|
+
#logAssetsDevServerMessage(data) {
|
|
355
|
+
const dataString = data.toString();
|
|
356
|
+
const lines = dataString.split("\n");
|
|
357
|
+
lines.forEach((line) => {
|
|
358
|
+
if (line.trim()) {
|
|
359
|
+
console.log(line);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Set a custom CLI UI logger
|
|
365
|
+
*/
|
|
366
|
+
setLogger(logger) {
|
|
367
|
+
this.#logger = logger;
|
|
368
|
+
return this;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Starts the assets bundler server. The assets bundler server process is
|
|
372
|
+
* considered as the secondary process and therefore we do not perform
|
|
373
|
+
* any cleanup if it dies.
|
|
374
|
+
*/
|
|
375
|
+
start() {
|
|
376
|
+
if (!this.#options?.enabled) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
this.#logger.info(`starting "${this.#options.driver}" dev server...`);
|
|
380
|
+
this.#devServer = run(this.#cwd, {
|
|
381
|
+
script: this.#options.cmd,
|
|
382
|
+
/**
|
|
383
|
+
* We do not inherit the stdio for vite and encore, because in
|
|
384
|
+
* inherit mode they own the stdin and interrupts the
|
|
385
|
+
* `Ctrl + C` command.
|
|
386
|
+
*/
|
|
387
|
+
stdio: "pipe",
|
|
388
|
+
scriptArgs: this.#options.args
|
|
389
|
+
});
|
|
390
|
+
this.#devServer.stdout?.on("data", (data) => {
|
|
391
|
+
if (this.#options.driver === "vite") {
|
|
392
|
+
this.#logViteDevServerMessage(data);
|
|
393
|
+
} else {
|
|
394
|
+
this.#logAssetsDevServerMessage(data);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
this.#devServer.stderr?.on("data", (data) => {
|
|
398
|
+
if (this.#options.driver === "vite") {
|
|
399
|
+
this.#logViteDevServerMessage(data);
|
|
400
|
+
} else {
|
|
401
|
+
this.#logAssetsDevServerMessage(data);
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
this.#devServer.then((result) => {
|
|
405
|
+
this.#logger.warning(
|
|
406
|
+
`"${this.#options.driver}" dev server closed with status code "${result.exitCode}"`
|
|
407
|
+
);
|
|
408
|
+
}).catch((error) => {
|
|
409
|
+
this.#logger.warning(`unable to connect to "${this.#options.driver}" dev server`);
|
|
410
|
+
this.#logger.fatal(error);
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Stop the dev server
|
|
415
|
+
*/
|
|
416
|
+
stop() {
|
|
417
|
+
if (this.#devServer) {
|
|
418
|
+
this.#devServer.removeAllListeners();
|
|
419
|
+
this.#devServer.kill("SIGKILL");
|
|
420
|
+
this.#devServer = void 0;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
// src/dev_server.ts
|
|
426
|
+
var ui3 = cliui3();
|
|
427
|
+
var DevServer = class {
|
|
428
|
+
#cwd;
|
|
429
|
+
#logger = ui3.logger;
|
|
430
|
+
#options;
|
|
431
|
+
/**
|
|
432
|
+
* Flag to know if the dev server is running in watch
|
|
433
|
+
* mode
|
|
434
|
+
*/
|
|
435
|
+
#isWatching = false;
|
|
436
|
+
/**
|
|
437
|
+
* Script file to start the development server
|
|
438
|
+
*/
|
|
439
|
+
#scriptFile = "bin/server.js";
|
|
440
|
+
/**
|
|
441
|
+
* Picomatch matcher function to know if a file path is a
|
|
442
|
+
* meta file with reloadServer option enabled
|
|
443
|
+
*/
|
|
444
|
+
#isMetaFileWithReloadsEnabled;
|
|
445
|
+
/**
|
|
446
|
+
* Picomatch matcher function to know if a file path is a
|
|
447
|
+
* meta file with reloadServer option disabled
|
|
448
|
+
*/
|
|
449
|
+
#isMetaFileWithReloadsDisabled;
|
|
450
|
+
/**
|
|
451
|
+
* External listeners that are invoked when child process
|
|
452
|
+
* gets an error or closes
|
|
453
|
+
*/
|
|
454
|
+
#onError;
|
|
455
|
+
#onClose;
|
|
456
|
+
/**
|
|
457
|
+
* Reference to the child process
|
|
458
|
+
*/
|
|
459
|
+
#httpServer;
|
|
460
|
+
/**
|
|
461
|
+
* Reference to the watcher
|
|
462
|
+
*/
|
|
463
|
+
#watcher;
|
|
464
|
+
/**
|
|
465
|
+
* Reference to the assets server
|
|
466
|
+
*/
|
|
467
|
+
#assetsServer;
|
|
468
|
+
/**
|
|
469
|
+
* Getting reference to colors library from logger
|
|
470
|
+
*/
|
|
471
|
+
get #colors() {
|
|
472
|
+
return this.#logger.getColors();
|
|
473
|
+
}
|
|
474
|
+
constructor(cwd, options) {
|
|
475
|
+
this.#cwd = cwd;
|
|
476
|
+
this.#options = options;
|
|
477
|
+
this.#isMetaFileWithReloadsEnabled = picomatch(
|
|
478
|
+
(this.#options.metaFiles || []).filter(({ reloadServer }) => reloadServer === true).map(({ pattern }) => pattern)
|
|
479
|
+
);
|
|
480
|
+
this.#isMetaFileWithReloadsDisabled = picomatch(
|
|
481
|
+
(this.#options.metaFiles || []).filter(({ reloadServer }) => reloadServer !== true).map(({ pattern }) => pattern)
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Inspect if child process message is from AdonisJS HTTP server
|
|
486
|
+
*/
|
|
487
|
+
#isAdonisJSReadyMessage(message) {
|
|
488
|
+
return message !== null && typeof message === "object" && "isAdonisJS" in message && "environment" in message && message.environment === "web";
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Conditionally clear the terminal screen
|
|
492
|
+
*/
|
|
493
|
+
#clearScreen() {
|
|
494
|
+
if (this.#options.clearScreen) {
|
|
495
|
+
process.stdout.write("\x1Bc");
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Starts the HTTP server
|
|
500
|
+
*/
|
|
501
|
+
#startHTTPServer(port, mode) {
|
|
502
|
+
this.#httpServer = runNode(this.#cwd, {
|
|
503
|
+
script: this.#scriptFile,
|
|
504
|
+
env: { PORT: port, ...this.#options.env },
|
|
505
|
+
nodeArgs: this.#options.nodeArgs,
|
|
506
|
+
scriptArgs: this.#options.scriptArgs
|
|
507
|
+
});
|
|
508
|
+
this.#httpServer.on("message", (message) => {
|
|
509
|
+
if (this.#isAdonisJSReadyMessage(message)) {
|
|
510
|
+
const host = message.host === "0.0.0.0" ? "127.0.0.1" : message.host;
|
|
511
|
+
const displayMessage = ui3.sticker().useColors(this.#colors).useRenderer(this.#logger.getRenderer()).add(`Server address: ${this.#colors.cyan(`http://${host}:${message.port}`)}`).add(
|
|
512
|
+
`File system watcher: ${this.#colors.cyan(
|
|
513
|
+
`${this.#isWatching ? "enabled" : "disabled"}`
|
|
514
|
+
)}`
|
|
515
|
+
);
|
|
516
|
+
if (message.duration) {
|
|
517
|
+
displayMessage.add(`Ready in: ${this.#colors.cyan(prettyHrtime(message.duration))}`);
|
|
518
|
+
}
|
|
519
|
+
displayMessage.render();
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
this.#httpServer.then((result) => {
|
|
523
|
+
if (mode === "nonblocking") {
|
|
524
|
+
this.#onClose?.(result.exitCode);
|
|
525
|
+
this.#watcher?.close();
|
|
526
|
+
this.#assetsServer?.stop();
|
|
527
|
+
} else {
|
|
528
|
+
this.#logger.info("Underlying HTTP server closed. Still watching for changes");
|
|
529
|
+
}
|
|
530
|
+
}).catch((error) => {
|
|
531
|
+
if (mode === "nonblocking") {
|
|
532
|
+
this.#onError?.(error);
|
|
533
|
+
this.#watcher?.close();
|
|
534
|
+
this.#assetsServer?.stop();
|
|
535
|
+
} else {
|
|
536
|
+
this.#logger.info("Underlying HTTP server died. Still watching for changes");
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Starts the assets server
|
|
542
|
+
*/
|
|
543
|
+
#startAssetsServer() {
|
|
544
|
+
this.#assetsServer = new AssetsDevServer(this.#cwd, this.#options.assets);
|
|
545
|
+
this.#assetsServer.setLogger(this.#logger);
|
|
546
|
+
this.#assetsServer.start();
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Restarts the HTTP server in the watch mode. Do not call this
|
|
550
|
+
* method when not in watch mode
|
|
551
|
+
*/
|
|
552
|
+
#restartHTTPServer(port) {
|
|
553
|
+
if (this.#httpServer) {
|
|
554
|
+
this.#httpServer.removeAllListeners();
|
|
555
|
+
this.#httpServer.kill("SIGKILL");
|
|
556
|
+
}
|
|
557
|
+
this.#startHTTPServer(port, "blocking");
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Handles a non TypeScript file change
|
|
561
|
+
*/
|
|
562
|
+
#handleFileChange(action, port, relativePath) {
|
|
563
|
+
if (isDotEnvFile(relativePath)) {
|
|
564
|
+
this.#clearScreen();
|
|
565
|
+
this.#logger.log(`${this.#colors.green(action)} ${relativePath}`);
|
|
566
|
+
this.#restartHTTPServer(port);
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
if (this.#isMetaFileWithReloadsEnabled(relativePath)) {
|
|
570
|
+
this.#clearScreen();
|
|
571
|
+
this.#logger.log(`${this.#colors.green(action)} ${relativePath}`);
|
|
572
|
+
this.#restartHTTPServer(port);
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
if (this.#isMetaFileWithReloadsDisabled(relativePath)) {
|
|
576
|
+
this.#clearScreen();
|
|
577
|
+
this.#logger.log(`${this.#colors.green(action)} ${relativePath}`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Handles TypeScript source file change
|
|
582
|
+
*/
|
|
583
|
+
#handleSourceFileChange(action, port, relativePath) {
|
|
584
|
+
this.#clearScreen();
|
|
585
|
+
this.#logger.log(`${this.#colors.green(action)} ${relativePath}`);
|
|
586
|
+
this.#restartHTTPServer(port);
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Set a custom CLI UI logger
|
|
590
|
+
*/
|
|
591
|
+
setLogger(logger) {
|
|
592
|
+
this.#logger = logger;
|
|
593
|
+
this.#assetsServer?.setLogger(logger);
|
|
594
|
+
return this;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Add listener to get notified when dev server is
|
|
598
|
+
* closed
|
|
599
|
+
*/
|
|
600
|
+
onClose(callback) {
|
|
601
|
+
this.#onClose = callback;
|
|
602
|
+
return this;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Add listener to get notified when dev server exists
|
|
606
|
+
* with an error
|
|
607
|
+
*/
|
|
608
|
+
onError(callback) {
|
|
609
|
+
this.#onError = callback;
|
|
610
|
+
return this;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Close watchers and running child processes
|
|
614
|
+
*/
|
|
615
|
+
async close() {
|
|
616
|
+
await this.#watcher?.close();
|
|
617
|
+
this.#assetsServer?.stop();
|
|
618
|
+
if (this.#httpServer) {
|
|
619
|
+
this.#httpServer.removeAllListeners();
|
|
620
|
+
this.#httpServer.kill("SIGKILL");
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Start the development server
|
|
625
|
+
*/
|
|
626
|
+
async start() {
|
|
627
|
+
this.#clearScreen();
|
|
628
|
+
this.#logger.info("starting HTTP server...");
|
|
629
|
+
this.#startHTTPServer(String(await getPort(this.#cwd)), "nonblocking");
|
|
630
|
+
this.#startAssetsServer();
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Start the development server in watch mode
|
|
634
|
+
*/
|
|
635
|
+
async startAndWatch(ts, options) {
|
|
636
|
+
const port = String(await getPort(this.#cwd));
|
|
637
|
+
this.#isWatching = true;
|
|
638
|
+
this.#clearScreen();
|
|
639
|
+
this.#logger.info("starting HTTP server...");
|
|
640
|
+
this.#startHTTPServer(port, "blocking");
|
|
641
|
+
this.#startAssetsServer();
|
|
642
|
+
const output = watch(this.#cwd, ts, options || {});
|
|
643
|
+
if (!output) {
|
|
644
|
+
this.#onClose?.(1);
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
this.#watcher = output.chokidar;
|
|
648
|
+
output.watcher.on("watcher:ready", () => {
|
|
649
|
+
this.#logger.info("watching file system for changes...");
|
|
650
|
+
});
|
|
651
|
+
output.chokidar.on("error", (error) => {
|
|
652
|
+
this.#logger.warning("file system watcher failure");
|
|
653
|
+
this.#logger.fatal(error);
|
|
654
|
+
this.#onError?.(error);
|
|
655
|
+
output.chokidar.close();
|
|
656
|
+
});
|
|
657
|
+
output.watcher.on(
|
|
658
|
+
"source:add",
|
|
659
|
+
({ relativePath }) => this.#handleSourceFileChange("add", port, relativePath)
|
|
660
|
+
);
|
|
661
|
+
output.watcher.on(
|
|
662
|
+
"source:change",
|
|
663
|
+
({ relativePath }) => this.#handleSourceFileChange("update", port, relativePath)
|
|
664
|
+
);
|
|
665
|
+
output.watcher.on(
|
|
666
|
+
"source:unlink",
|
|
667
|
+
({ relativePath }) => this.#handleSourceFileChange("delete", port, relativePath)
|
|
668
|
+
);
|
|
669
|
+
output.watcher.on(
|
|
670
|
+
"add",
|
|
671
|
+
({ relativePath }) => this.#handleFileChange("add", port, relativePath)
|
|
672
|
+
);
|
|
673
|
+
output.watcher.on(
|
|
674
|
+
"change",
|
|
675
|
+
({ relativePath }) => this.#handleFileChange("update", port, relativePath)
|
|
676
|
+
);
|
|
677
|
+
output.watcher.on(
|
|
678
|
+
"unlink",
|
|
679
|
+
({ relativePath }) => this.#handleFileChange("delete", port, relativePath)
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
// src/test_runner.ts
|
|
685
|
+
import picomatch2 from "picomatch";
|
|
686
|
+
import { cliui as cliui4 } from "@poppinss/cliui";
|
|
687
|
+
var ui4 = cliui4();
|
|
688
|
+
var TestRunner = class {
|
|
689
|
+
#cwd;
|
|
690
|
+
#logger = ui4.logger;
|
|
691
|
+
#options;
|
|
692
|
+
/**
|
|
693
|
+
* The script file to run as a child process
|
|
694
|
+
*/
|
|
695
|
+
#scriptFile = "bin/test.js";
|
|
696
|
+
/**
|
|
697
|
+
* Pico matcher function to check if the filepath is
|
|
698
|
+
* part of the `metaFiles` glob patterns
|
|
699
|
+
*/
|
|
700
|
+
#isMetaFile;
|
|
701
|
+
/**
|
|
702
|
+
* Pico matcher function to check if the filepath is
|
|
703
|
+
* part of a test file.
|
|
704
|
+
*/
|
|
705
|
+
#isTestFile;
|
|
706
|
+
/**
|
|
707
|
+
* Arguments to pass to the "bin/test.js" file.
|
|
708
|
+
*/
|
|
709
|
+
#scriptArgs;
|
|
710
|
+
/**
|
|
711
|
+
* Set of initial filters applied when running the test
|
|
712
|
+
* command. In watch mode, we will append an additional
|
|
713
|
+
* filter to run tests only for the file that has been
|
|
714
|
+
* changed.
|
|
715
|
+
*/
|
|
716
|
+
#initialFiltersArgs;
|
|
717
|
+
/**
|
|
718
|
+
* In watch mode, after a file is changed, we wait for the current
|
|
719
|
+
* set of tests to finish before triggering a re-run. Therefore,
|
|
720
|
+
* we use this flag to know if we are already busy in running
|
|
721
|
+
* tests and ignore file-changes.
|
|
722
|
+
*/
|
|
723
|
+
#isBusy = false;
|
|
724
|
+
/**
|
|
725
|
+
* External listeners that are invoked when child process
|
|
726
|
+
* gets an error or closes
|
|
727
|
+
*/
|
|
728
|
+
#onError;
|
|
729
|
+
#onClose;
|
|
730
|
+
/**
|
|
731
|
+
* Reference to the test script child process
|
|
732
|
+
*/
|
|
733
|
+
#testScript;
|
|
734
|
+
/**
|
|
735
|
+
* Reference to the watcher
|
|
736
|
+
*/
|
|
737
|
+
#watcher;
|
|
738
|
+
/**
|
|
739
|
+
* Reference to the assets server
|
|
740
|
+
*/
|
|
741
|
+
#assetsServer;
|
|
742
|
+
/**
|
|
743
|
+
* Getting reference to colors library from logger
|
|
744
|
+
*/
|
|
745
|
+
get #colors() {
|
|
746
|
+
return this.#logger.getColors();
|
|
747
|
+
}
|
|
748
|
+
constructor(cwd, options) {
|
|
749
|
+
this.#cwd = cwd;
|
|
750
|
+
this.#options = options;
|
|
751
|
+
this.#isMetaFile = picomatch2((this.#options.metaFiles || []).map(({ pattern }) => pattern));
|
|
752
|
+
this.#isTestFile = picomatch2(
|
|
753
|
+
this.#options.suites.filter((suite) => {
|
|
754
|
+
if (this.#options.filters.suites) {
|
|
755
|
+
return this.#options.filters.suites.includes(suite.name);
|
|
756
|
+
}
|
|
757
|
+
return true;
|
|
758
|
+
}).map((suite) => suite.files).flat(1)
|
|
759
|
+
);
|
|
760
|
+
this.#scriptArgs = this.#convertOptionsToArgs().concat(this.#options.scriptArgs);
|
|
761
|
+
this.#initialFiltersArgs = this.#convertFiltersToArgs(this.#options.filters);
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Convert test runner options to the CLI args
|
|
765
|
+
*/
|
|
766
|
+
#convertOptionsToArgs() {
|
|
767
|
+
const args = [];
|
|
768
|
+
if (this.#options.reporters) {
|
|
769
|
+
args.push("--reporters");
|
|
770
|
+
args.push(this.#options.reporters.join(","));
|
|
771
|
+
}
|
|
772
|
+
if (this.#options.timeout !== void 0) {
|
|
773
|
+
args.push("--timeout");
|
|
774
|
+
args.push(String(this.#options.timeout));
|
|
775
|
+
}
|
|
776
|
+
if (this.#options.failed) {
|
|
777
|
+
args.push("--failed");
|
|
778
|
+
}
|
|
779
|
+
if (this.#options.retries !== void 0) {
|
|
780
|
+
args.push("--retries");
|
|
781
|
+
args.push(String(this.#options.retries));
|
|
782
|
+
}
|
|
783
|
+
return args;
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* Converts all known filters to CLI args.
|
|
787
|
+
*
|
|
788
|
+
* The following code snippet may seem like repetitive code. But, it
|
|
789
|
+
* is done intentionally to have visibility around how each filter
|
|
790
|
+
* is converted to an arg.
|
|
791
|
+
*/
|
|
792
|
+
#convertFiltersToArgs(filters) {
|
|
793
|
+
const args = [];
|
|
794
|
+
if (filters.suites) {
|
|
795
|
+
args.push(...filters.suites);
|
|
796
|
+
}
|
|
797
|
+
if (filters.files) {
|
|
798
|
+
args.push("--files");
|
|
799
|
+
args.push(filters.files.join(","));
|
|
800
|
+
}
|
|
801
|
+
if (filters.groups) {
|
|
802
|
+
args.push("--groups");
|
|
803
|
+
args.push(filters.groups.join(","));
|
|
804
|
+
}
|
|
805
|
+
if (filters.tags) {
|
|
806
|
+
args.push("--tags");
|
|
807
|
+
args.push(filters.tags.join(","));
|
|
808
|
+
}
|
|
809
|
+
if (filters.tests) {
|
|
810
|
+
args.push("--tests");
|
|
811
|
+
args.push(filters.tests.join(","));
|
|
812
|
+
}
|
|
813
|
+
return args;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Conditionally clear the terminal screen
|
|
817
|
+
*/
|
|
818
|
+
#clearScreen() {
|
|
819
|
+
if (this.#options.clearScreen) {
|
|
820
|
+
process.stdout.write("\x1Bc");
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Runs tests
|
|
825
|
+
*/
|
|
826
|
+
#runTests(port, mode, filters) {
|
|
827
|
+
this.#isBusy = true;
|
|
828
|
+
const scriptArgs = filters ? this.#convertFiltersToArgs(filters).concat(this.#scriptArgs) : this.#initialFiltersArgs.concat(this.#scriptArgs);
|
|
829
|
+
this.#testScript = runNode(this.#cwd, {
|
|
830
|
+
script: this.#scriptFile,
|
|
831
|
+
env: { PORT: port, ...this.#options.env },
|
|
832
|
+
nodeArgs: this.#options.nodeArgs,
|
|
833
|
+
scriptArgs
|
|
834
|
+
});
|
|
835
|
+
this.#testScript.then((result) => {
|
|
836
|
+
if (mode === "nonblocking") {
|
|
837
|
+
this.#onClose?.(result.exitCode);
|
|
838
|
+
this.close();
|
|
839
|
+
}
|
|
840
|
+
}).catch((error) => {
|
|
841
|
+
if (mode === "nonblocking") {
|
|
842
|
+
this.#onError?.(error);
|
|
843
|
+
this.close();
|
|
844
|
+
}
|
|
845
|
+
}).finally(() => {
|
|
846
|
+
this.#isBusy = false;
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
/**
|
|
850
|
+
* Re-run tests with additional inline filters. Should be
|
|
851
|
+
* executed in watch mode only.
|
|
852
|
+
*/
|
|
853
|
+
#rerunTests(port, filters) {
|
|
854
|
+
if (this.#testScript) {
|
|
855
|
+
this.#testScript.removeAllListeners();
|
|
856
|
+
this.#testScript.kill("SIGKILL");
|
|
857
|
+
}
|
|
858
|
+
this.#runTests(port, "blocking", filters);
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Starts the assets server
|
|
862
|
+
*/
|
|
863
|
+
#startAssetsServer() {
|
|
864
|
+
this.#assetsServer = new AssetsDevServer(this.#cwd, this.#options.assets);
|
|
865
|
+
this.#assetsServer.setLogger(this.#logger);
|
|
866
|
+
this.#assetsServer.start();
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Handles a non TypeScript file change
|
|
870
|
+
*/
|
|
871
|
+
#handleFileChange(action, port, relativePath) {
|
|
872
|
+
if (this.#isBusy) {
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
if (isDotEnvFile(relativePath) || this.#isMetaFile(relativePath)) {
|
|
876
|
+
this.#clearScreen();
|
|
877
|
+
this.#logger.log(`${this.#colors.green(action)} ${relativePath}`);
|
|
878
|
+
this.#rerunTests(port);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Handles TypeScript source file change
|
|
883
|
+
*/
|
|
884
|
+
#handleSourceFileChange(action, port, relativePath) {
|
|
885
|
+
if (this.#isBusy) {
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
this.#clearScreen();
|
|
889
|
+
this.#logger.log(`${this.#colors.green(action)} ${relativePath}`);
|
|
890
|
+
if (this.#isTestFile(relativePath)) {
|
|
891
|
+
this.#rerunTests(port, {
|
|
892
|
+
...this.#options.filters,
|
|
893
|
+
files: [relativePath]
|
|
894
|
+
});
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
this.#rerunTests(port);
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Set a custom CLI UI logger
|
|
901
|
+
*/
|
|
902
|
+
setLogger(logger) {
|
|
903
|
+
this.#logger = logger;
|
|
904
|
+
this.#assetsServer?.setLogger(logger);
|
|
905
|
+
return this;
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Add listener to get notified when dev server is
|
|
909
|
+
* closed
|
|
910
|
+
*/
|
|
911
|
+
onClose(callback) {
|
|
912
|
+
this.#onClose = callback;
|
|
913
|
+
return this;
|
|
914
|
+
}
|
|
915
|
+
/**
|
|
916
|
+
* Add listener to get notified when dev server exists
|
|
917
|
+
* with an error
|
|
918
|
+
*/
|
|
919
|
+
onError(callback) {
|
|
920
|
+
this.#onError = callback;
|
|
921
|
+
return this;
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Close watchers and running child processes
|
|
925
|
+
*/
|
|
926
|
+
async close() {
|
|
927
|
+
await this.#watcher?.close();
|
|
928
|
+
this.#assetsServer?.stop();
|
|
929
|
+
if (this.#testScript) {
|
|
930
|
+
this.#testScript.removeAllListeners();
|
|
931
|
+
this.#testScript.kill("SIGKILL");
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* Runs tests
|
|
936
|
+
*/
|
|
937
|
+
async run() {
|
|
938
|
+
const port = String(await getPort(this.#cwd));
|
|
939
|
+
this.#clearScreen();
|
|
940
|
+
this.#startAssetsServer();
|
|
941
|
+
this.#logger.info("booting application to run tests...");
|
|
942
|
+
this.#runTests(port, "nonblocking");
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Run tests in watch mode
|
|
946
|
+
*/
|
|
947
|
+
async runAndWatch(ts, options) {
|
|
948
|
+
const port = String(await getPort(this.#cwd));
|
|
949
|
+
this.#clearScreen();
|
|
950
|
+
this.#startAssetsServer();
|
|
951
|
+
this.#logger.info("booting application to run tests...");
|
|
952
|
+
this.#runTests(port, "blocking");
|
|
953
|
+
const output = watch(this.#cwd, ts, options || {});
|
|
954
|
+
if (!output) {
|
|
955
|
+
this.#onClose?.(1);
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
this.#watcher = output.chokidar;
|
|
959
|
+
output.watcher.on("watcher:ready", () => {
|
|
960
|
+
this.#logger.info("watching file system for changes...");
|
|
961
|
+
});
|
|
962
|
+
output.chokidar.on("error", (error) => {
|
|
963
|
+
this.#logger.warning("file system watcher failure");
|
|
964
|
+
this.#logger.fatal(error);
|
|
965
|
+
this.#onError?.(error);
|
|
966
|
+
output.chokidar.close();
|
|
967
|
+
});
|
|
968
|
+
output.watcher.on(
|
|
969
|
+
"source:add",
|
|
970
|
+
({ relativePath }) => this.#handleSourceFileChange("add", port, relativePath)
|
|
971
|
+
);
|
|
972
|
+
output.watcher.on(
|
|
973
|
+
"source:change",
|
|
974
|
+
({ relativePath }) => this.#handleSourceFileChange("update", port, relativePath)
|
|
975
|
+
);
|
|
976
|
+
output.watcher.on(
|
|
977
|
+
"source:unlink",
|
|
978
|
+
({ relativePath }) => this.#handleSourceFileChange("delete", port, relativePath)
|
|
979
|
+
);
|
|
980
|
+
output.watcher.on(
|
|
981
|
+
"add",
|
|
982
|
+
({ relativePath }) => this.#handleFileChange("add", port, relativePath)
|
|
983
|
+
);
|
|
984
|
+
output.watcher.on(
|
|
985
|
+
"change",
|
|
986
|
+
({ relativePath }) => this.#handleFileChange("update", port, relativePath)
|
|
987
|
+
);
|
|
988
|
+
output.watcher.on(
|
|
989
|
+
"unlink",
|
|
990
|
+
({ relativePath }) => this.#handleFileChange("delete", port, relativePath)
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
};
|
|
994
|
+
export {
|
|
995
|
+
Bundler,
|
|
996
|
+
DevServer,
|
|
997
|
+
TestRunner
|
|
998
|
+
};
|
|
999
|
+
//# sourceMappingURL=index.js.map
|