Skip to content

Commit 4e31fd9

Browse files
authored
feat(cli): Add callbacks to cli (#56)
Closes #55 I rename `packages/cli/src/swc/index.ts` to `packages/cli/src/swc/bin.ts`, and export `swcDir` function via new `packages/cli/src/swc/index.ts` add doc here: swc-project/website#261
1 parent d096fdc commit 4e31fd9

File tree

6 files changed

+216
-59
lines changed

6 files changed

+216
-59
lines changed

packages/cli/bin/swc.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/usr/bin/env node
22

33
process.title = "swc";
4-
require("../lib/swc");
4+
require("../lib/swc/bin.js");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { swcDir } from "../index";
2+
3+
jest.mock("../compile", () => ({
4+
outputResult: jest.fn(),
5+
}));
6+
7+
let mockComplie: any;
8+
9+
jest.mock("../dirWorker", () => ({
10+
__esModule: true,
11+
default: () => mockComplie(),
12+
}));
13+
14+
const cliOptions: any = {
15+
outDir: "./.temp/",
16+
watch: false,
17+
filenames: ["./src/swcx/"],
18+
extensions: [".ts"],
19+
stripLeadingPaths: true,
20+
sync: true,
21+
};
22+
const swcOptions: any = {
23+
jsc: {
24+
target: "esnext",
25+
externalHelpers: false,
26+
},
27+
module: {
28+
type: "commonjs",
29+
},
30+
};
31+
32+
describe("dir callbacks", () => {
33+
it("onSuccess should be called", async () => {
34+
mockComplie = () => Promise.resolve(1); // mock complie success
35+
36+
const onSuccess = jest.fn();
37+
const onFail = jest.fn();
38+
39+
await swcDir({
40+
cliOptions: cliOptions,
41+
swcOptions: swcOptions,
42+
callbacks: {
43+
onSuccess,
44+
onFail,
45+
},
46+
});
47+
48+
expect(onSuccess.mock.calls).toHaveLength(1);
49+
expect(onFail.mock.calls).toHaveLength(0);
50+
});
51+
52+
it("onFail should be called", async () => {
53+
mockComplie = () => Promise.reject(new Error("fail")); // mock complie fail
54+
55+
const onSuccess = jest.fn();
56+
const onFail = jest.fn();
57+
58+
await swcDir({
59+
cliOptions: cliOptions,
60+
swcOptions: swcOptions,
61+
callbacks: {
62+
onSuccess,
63+
onFail,
64+
},
65+
});
66+
67+
expect(onSuccess.mock.calls).toHaveLength(0);
68+
expect(onFail.mock.calls).toHaveLength(1);
69+
});
70+
});

packages/cli/src/swc/bin.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import dirCommand from "./dir";
2+
import fileCommand from "./file";
3+
import parseArgs, { initProgram } from "./options";
4+
5+
initProgram();
6+
const opts = parseArgs(process.argv);
7+
const fn = opts.cliOptions.outDir ? dirCommand : fileCommand;
8+
9+
process.on("uncaughtException", function (err) {
10+
console.error(err);
11+
process.exit(1);
12+
});
13+
14+
fn(opts).catch((err: Error) => {
15+
console.error(err);
16+
process.exit(1);
17+
});

packages/cli/src/swc/dir.ts

+110-42
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { existsSync, promises } from "fs";
22
import { dirname, resolve } from "path";
33
import Piscina from "piscina";
44
import { CompileStatus } from "./constants";
5-
import { CliOptions } from "./options";
5+
import { Callbacks, CliOptions } from "./options";
66
import { exists, getDest } from "./util";
77
import handleCompile from "./dirWorker";
88
import {
@@ -53,7 +53,11 @@ async function beforeStartCompilation(cliOptions: CliOptions) {
5353
}
5454
}
5555

56-
async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
56+
async function initialCompilation(
57+
cliOptions: CliOptions,
58+
swcOptions: Options,
59+
callbacks?: Callbacks
60+
) {
5761
const {
5862
includeDotfiles,
5963
filenames,
@@ -70,6 +74,7 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
7074
} = cliOptions;
7175

7276
const results = new Map<string, CompileStatus>();
77+
const reasons = new Map<string, string>();
7378

7479
const start = process.hrtime();
7580
const sourceFiles = await globSources(
@@ -83,7 +88,6 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
8388
extensions,
8489
copyFiles
8590
);
86-
8791
if (sync) {
8892
for (const filename of compilable) {
8993
try {
@@ -97,7 +101,9 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
97101
});
98102
results.set(filename, result);
99103
} catch (err: any) {
100-
console.error(err.message);
104+
if (!callbacks?.onFail) {
105+
console.error(err.message);
106+
}
101107
results.set(filename, CompileStatus.Failed);
102108
}
103109
}
@@ -110,7 +116,9 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
110116
);
111117
results.set(filename, result);
112118
} catch (err: any) {
113-
console.error(err.message);
119+
if (!callbacks?.onFail) {
120+
console.error(err.message);
121+
}
114122
results.set(filename, CompileStatus.Failed);
115123
}
116124
}
@@ -134,7 +142,9 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
134142
outFileExtension,
135143
})
136144
.catch(err => {
137-
console.error(err.message);
145+
if (!callbacks?.onFail) {
146+
console.error(err.message);
147+
}
138148
throw err;
139149
})
140150
)
@@ -151,6 +161,7 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
151161
results.set(filename, result.value);
152162
} else {
153163
results.set(filename, CompileStatus.Failed);
164+
reasons.set(filename, result.reason.message);
154165
}
155166
});
156167

@@ -182,8 +193,9 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
182193
break;
183194
}
184195
}
196+
const duration = end[1] / 1000000;
185197

186-
if (!quiet && compiled + copied) {
198+
if (compiled + copied) {
187199
let message = "";
188200
if (compiled) {
189201
message += `Successfully compiled: ${compiled} ${
@@ -198,26 +210,40 @@ async function initialCompilation(cliOptions: CliOptions, swcOptions: Options) {
198210
}
199211
message += ` with swc (%dms)`;
200212

201-
console.log(message, (end[1] / 1000000).toFixed(2));
213+
if (callbacks?.onSuccess) {
214+
if (!failed) {
215+
callbacks.onSuccess({ duration, compiled, copied });
216+
}
217+
} else if (!quiet) {
218+
console.log(message, duration.toFixed(2));
219+
}
202220
}
203221

204222
if (failed) {
205-
console.log(
206-
`Failed to compile ${failed} ${
207-
failed !== 1 ? "files" : "file"
208-
} with swc.`
209-
);
210-
if (!watch) {
211-
const files = Array.from(results.entries())
212-
.filter(([, status]) => status === CompileStatus.Failed)
213-
.map(([filename, _]) => filename)
214-
.join("\n");
215-
throw new Error(`Failed to compile:\n${files}`);
223+
if (callbacks?.onFail) {
224+
callbacks.onFail({ duration, reasons });
225+
} else {
226+
console.log(
227+
`Failed to compile ${failed} ${
228+
failed !== 1 ? "files" : "file"
229+
} with swc.`
230+
);
231+
if (!watch) {
232+
const files = Array.from(results.entries())
233+
.filter(([, status]) => status === CompileStatus.Failed)
234+
.map(([filename, _]) => filename)
235+
.join("\n");
236+
throw new Error(`Failed to compile:\n${files}`);
237+
}
216238
}
217239
}
218240
}
219241

220-
async function watchCompilation(cliOptions: CliOptions, swcOptions: Options) {
242+
async function watchCompilation(
243+
cliOptions: CliOptions,
244+
swcOptions: Options,
245+
callbacks?: Callbacks
246+
) {
221247
const {
222248
includeDotfiles,
223249
filenames,
@@ -232,7 +258,9 @@ async function watchCompilation(cliOptions: CliOptions, swcOptions: Options) {
232258

233259
const watcher = await watchSources(filenames, includeDotfiles);
234260
watcher.on("ready", () => {
235-
if (!quiet) {
261+
if (callbacks?.onWatchReady) {
262+
callbacks.onWatchReady();
263+
} else if (!quiet) {
236264
console.info("Watching for file changes.");
237265
}
238266
});
@@ -264,8 +292,13 @@ async function watchCompilation(cliOptions: CliOptions, swcOptions: Options) {
264292
for (const type of ["add", "change"]) {
265293
watcher.on(type, async filename => {
266294
if (isCompilableExtension(filename, extensions)) {
295+
const start = process.hrtime();
296+
const getDuration = () => {
297+
const end = process.hrtime(start);
298+
const duration = end[1] / 1000000;
299+
return duration;
300+
};
267301
try {
268-
const start = process.hrtime();
269302
const result = await handleCompile({
270303
filename,
271304
outDir,
@@ -274,34 +307,67 @@ async function watchCompilation(cliOptions: CliOptions, swcOptions: Options) {
274307
swcOptions,
275308
outFileExtension,
276309
});
277-
if (!quiet && result === CompileStatus.Compiled) {
278-
const end = process.hrtime(start);
279-
console.log(
280-
`Successfully compiled ${filename} with swc (%dms)`,
281-
(end[1] / 1000000).toFixed(2)
282-
);
310+
const duration = getDuration();
311+
if (result === CompileStatus.Compiled) {
312+
if (callbacks?.onSuccess) {
313+
callbacks.onSuccess({
314+
duration,
315+
compiled: 1,
316+
filename,
317+
});
318+
} else if (!quiet) {
319+
console.log(
320+
`Successfully compiled ${filename} with swc (%dms)`,
321+
duration.toFixed(2)
322+
);
323+
}
324+
}
325+
} catch (error: any) {
326+
if (callbacks?.onFail) {
327+
const reasons = new Map<string, string>();
328+
reasons.set(filename, error.message);
329+
callbacks.onFail({ duration: getDuration(), reasons });
330+
} else {
331+
console.error(error.message);
283332
}
284-
} catch (err: any) {
285-
console.error(err.message);
286333
}
287334
} else if (copyFiles) {
335+
const start = process.hrtime();
336+
const getDuration = () => {
337+
const end = process.hrtime(start);
338+
const duration = end[1] / 1000000;
339+
return duration;
340+
};
288341
try {
289-
const start = process.hrtime();
290342
const result = await handleCopy(
291343
filename,
292344
outDir,
293345
stripLeadingPaths
294346
);
295-
if (!quiet && result === CompileStatus.Copied) {
296-
const end = process.hrtime(start);
297-
console.log(
298-
`Successfully copied ${filename} with swc (%dms)`,
299-
(end[1] / 1000000).toFixed(2)
300-
);
347+
if (result === CompileStatus.Copied) {
348+
const duration = getDuration();
349+
if (callbacks?.onSuccess) {
350+
callbacks.onSuccess({
351+
duration,
352+
copied: 1,
353+
filename,
354+
});
355+
} else if (!quiet) {
356+
console.log(
357+
`Successfully copied ${filename} with swc (%dms)`,
358+
duration.toFixed(2)
359+
);
360+
}
361+
}
362+
} catch (error: any) {
363+
if (callbacks?.onFail) {
364+
const reasons = new Map<string, string>();
365+
reasons.set(filename, error.message);
366+
callbacks.onFail({ duration: getDuration(), reasons });
367+
} else {
368+
console.error(`Failed to copy ${filename}`);
369+
console.error(error.message);
301370
}
302-
} catch (err: any) {
303-
console.error(`Failed to copy ${filename}`);
304-
console.error(err.message);
305371
}
306372
}
307373
});
@@ -311,16 +377,18 @@ async function watchCompilation(cliOptions: CliOptions, swcOptions: Options) {
311377
export default async function dir({
312378
cliOptions,
313379
swcOptions,
380+
callbacks,
314381
}: {
315382
cliOptions: CliOptions;
316383
swcOptions: Options;
384+
callbacks?: Callbacks;
317385
}) {
318386
const { watch } = cliOptions;
319387

320388
await beforeStartCompilation(cliOptions);
321-
await initialCompilation(cliOptions, swcOptions);
389+
await initialCompilation(cliOptions, swcOptions, callbacks);
322390

323391
if (watch) {
324-
await watchCompilation(cliOptions, swcOptions);
392+
await watchCompilation(cliOptions, swcOptions, callbacks);
325393
}
326394
}

packages/cli/src/swc/index.ts

+2-16
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,3 @@
1-
import dirCommand from "./dir";
2-
import fileCommand from "./file";
3-
import parseArgs, { initProgram } from "./options";
1+
import swcDir from "./dir";
42

5-
initProgram();
6-
const opts = parseArgs(process.argv);
7-
const fn = opts.cliOptions.outDir ? dirCommand : fileCommand;
8-
9-
process.on("uncaughtException", function (err) {
10-
console.error(err);
11-
process.exit(1);
12-
});
13-
14-
fn(opts).catch((err: Error) => {
15-
console.error(err);
16-
process.exit(1);
17-
});
3+
export { swcDir };

0 commit comments

Comments
 (0)