forked from OKEAMAH/prettier
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun-cli.js
More file actions
162 lines (139 loc) · 3.83 KB
/
run-cli.js
File metadata and controls
162 lines (139 loc) · 3.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import path from "node:path";
import url from "node:url";
import { Worker } from "node:worker_threads";
const CLI_WORKER_FILE = new URL("./cli-worker.js", import.meta.url);
const INTEGRATION_TEST_DIRECTORY = url.fileURLToPath(
new URL("./", import.meta.url),
);
const streamToString = (stream) =>
new Promise((resolve, reject) => {
let result = "";
stream.on("data", (data) => {
result += data.toString();
});
stream.on("end", () => {
resolve(result);
});
stream.on("error", (error) => {
reject(error);
});
});
const removeFinalNewLine = (string) =>
string.endsWith("\n") ? string.slice(0, -1) : string;
function runCliWorker(dir, args, options) {
const result = {
status: undefined,
stdout: "",
stderr: "",
write: [],
};
const worker = new Worker(CLI_WORKER_FILE, {
argv: args,
execArgv: ["--trace-deprecation"],
stdout: true,
stderr: true,
env: {
...process.env,
FORCE_COLOR: 0,
},
workerData: {
dir,
options,
},
trackUnmanagedFds: false,
});
worker.on("message", ({ action, data }) => {
if (action === "write-file") {
result.write.push(data);
}
});
return new Promise((resolve, reject) => {
worker.on("exit", async (code) => {
result.status = code;
result.stdout = removeFinalNewLine(await streamToString(worker.stdout));
result.stderr = removeFinalNewLine(await streamToString(worker.stderr));
resolve(result);
});
worker.on("error", (error) => {
reject(error);
});
worker.postMessage("run");
});
}
async function runPrettierCli(dir, args, options) {
dir = path.resolve(INTEGRATION_TEST_DIRECTORY, dir);
args = Array.isArray(args) ? args : [args];
// Worker doesn't support `chdir`
const cwd = process.cwd();
process.chdir(dir);
try {
return await runCliWorker(dir, args, options);
} finally {
process.chdir(cwd);
}
}
let runningCli;
function runCli(dir, args = [], options = {}) {
let promise;
const getters = {
get status() {
return run().then(({ status }) => status);
},
get stdout() {
return run().then(({ stdout }) => stdout);
},
get stderr() {
return run().then(({ stderr }) => stderr);
},
get write() {
return run().then(({ write }) => write);
},
test: testResult,
then(onFulfilled, onRejected) {
return run().then(onFulfilled, onRejected);
},
};
return getters;
function run() {
if (runningCli) {
throw new Error("Please wait for previous CLI to exit.");
}
if (!promise) {
promise = runPrettierCli(dir, args, options).finally(() => {
runningCli = undefined;
});
runningCli = promise;
}
return promise;
}
function testResult(testOptions) {
for (const name of ["status", "stdout", "stderr", "write"]) {
test(`${options.title || ""}(${name})`, async () => {
const result = await run();
let value = result[name];
// \r is trimmed from jest snapshots by default;
// manually replacing this character with /*CR*/ to test its true presence
// If ignoreLineEndings is specified, \r is simply deleted instead
if (name === "stdout" || name === "stderr") {
value = result[name].replace(
/\r/gu,
options.ignoreLineEndings ? "" : "/*CR*/",
);
}
if (name in testOptions) {
if (name === "status" && testOptions[name] === "non-zero") {
expect(value).not.toBe(0);
} else if (typeof testOptions[name] === "function") {
testOptions[name](value);
} else {
expect(value).toEqual(testOptions[name]);
}
} else {
expect(value).toMatchSnapshot();
}
});
}
return getters;
}
}
export default runCli;