Skip to content

Commit 31a6a63

Browse files
committed
chore: add reformatting script
1 parent df8b9f6 commit 31a6a63

File tree

3 files changed

+322
-1
lines changed

3 files changed

+322
-1
lines changed

.prettierignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
meteor/.meteor
2+
**/dist/**
3+
4+
**/node_modules/**
5+

packages/job-worker/tsconfig.build.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
},
1212
"resolveJsonModule": true,
1313
"types": ["node"],
14-
"skipLibCheck": true
14+
"skipLibCheck": true,
15+
"esModuleInterop": true
1516
}
1617
}

scripts/reformat.mjs

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
import path from "path";
2+
import fs from "fs/promises";
3+
import { glob } from "glob";
4+
import cp from "child_process";
5+
6+
/*
7+
8+
Instructions for applying reformatting:
9+
10+
1. Cherry-pick the commit "chore: update dependencies and reformatting script"
11+
2. Run `yarn postinstall`
12+
3. Apply reformatting automatically:
13+
a. Run `node scripts/reformat.mjs --write`
14+
b. Run `node scripts/reformat.mjs --write` again :)
15+
c. commit the result
16+
"chore: reformat code using reformat.mjs"
17+
4. cherry-pick the commits:
18+
* "chore: apply various fixes after reformatting"
19+
20+
*/
21+
22+
const writeChanges = Boolean(process.argv.find((arg) => arg === "--write"));
23+
24+
if (!writeChanges) console.log('Dry run, use "--write" to apply changes');
25+
26+
let exitCode = 0;
27+
let maxCount = 99999;
28+
29+
async function main() {
30+
// First, prettier reformat all files:
31+
try {
32+
console.log("Prettier formatting ---------------------------------");
33+
await prettierReformatFiles();
34+
} catch (e) {
35+
console.error(e);
36+
exitCode = 1;
37+
}
38+
39+
try {
40+
console.log("Custom formatting -----------------------------------");
41+
await customReformatFiles();
42+
} catch (e) {
43+
console.error(e);
44+
exitCode = 1;
45+
}
46+
}
47+
48+
// ----------------------------------------------------------------------------
49+
async function prettierReformatFiles() {
50+
// await runCmd(`npx prettier --check "./**/*.{ts,tsx,json,md}"`);
51+
await runCmd(
52+
`npx prettier ${
53+
writeChanges ? "--write" : "--check"
54+
} "./**/*.{ts,tsx,js,jsx,json,css,scss,md,html}"`
55+
);
56+
}
57+
async function customReformatFiles() {
58+
// include a
59+
const files = await glob(["**/*.ts", "**/*.tsx"], {
60+
ignore: ["**/node_modules/**", "**/dist/**"],
61+
});
62+
63+
console.log(`Found ${files.length} files...`);
64+
65+
let modified = [];
66+
67+
for (const filename of files) {
68+
maxCount--;
69+
if (maxCount < 0) break;
70+
71+
// if (!filename.includes("App.tsx")) continue;
72+
73+
console.log(filename);
74+
75+
const filePath = path.resolve(filename);
76+
77+
const fileContentOrg = await fs.readFile(filePath, "utf-8");
78+
let fileContent = fileContentOrg;
79+
// console.log("fileContent", fileContent);
80+
81+
const maybeReplaceCb = async (match) => {
82+
const matchStr = match[0];
83+
84+
// console.log("matchStr", matchStr);
85+
86+
if (
87+
// Already fixed:
88+
matchStr.includes(".js'") ||
89+
matchStr.includes(".jsx'") ||
90+
matchStr.includes(".ts'") ||
91+
matchStr.includes(".tsx'") ||
92+
matchStr.includes(".json'") ||
93+
matchStr.includes(".scss'")
94+
)
95+
return undefined;
96+
97+
if (
98+
// Must be a relative file name:
99+
!matchStr.includes("'./") &&
100+
!matchStr.includes("'..") &&
101+
!matchStr.includes("'.'")
102+
)
103+
return undefined;
104+
105+
let replaceFile = undefined;
106+
107+
// console.log("aaaa");
108+
let orgTarget = path.resolve(path.dirname(filePath), match[1]);
109+
110+
// if (await fsExists())
111+
// console.log("orgTarget", filePath, match[1], orgTarget);
112+
try {
113+
if (
114+
(await fsExists(orgTarget)) &&
115+
(await isDirectory(orgTarget)) &&
116+
!(await fsExists(orgTarget + ".ts")) // in case there is a lib.ts and a lib directory
117+
) {
118+
// console.log("IS DIR", orgTarget);
119+
120+
// is a directory
121+
122+
let isAlreadyAFile = false;
123+
// now check if it also is a file
124+
const tsFilePaths = [`${orgTarget}.ts`, `${orgTarget}.tsx`];
125+
for (const tsFilePath of tsFilePaths) {
126+
// console.log("tsFilePath", tsFilePath);
127+
if (await fsExists(tsFilePath)) {
128+
// console.log("IS ALSO A TS FILE", tsFilePath);
129+
130+
isAlreadyAFile = true;
131+
}
132+
}
133+
134+
if (!isAlreadyAFile) {
135+
// now check if there is an index file in it
136+
const indexFiles = [
137+
path.join(orgTarget, "index.ts"),
138+
path.join(orgTarget, "index.tsx"),
139+
];
140+
for (const indexFile of indexFiles) {
141+
// console.log("EXISTS?", indexFile);
142+
if (await fsExists(indexFile)) {
143+
// console.log("EXISTS", indexFile);
144+
145+
replaceFile = match[1] + "/index.js";
146+
break;
147+
}
148+
}
149+
}
150+
}
151+
} catch (e) {
152+
console.log("orgTarget", filePath, match[1], orgTarget);
153+
throw e;
154+
}
155+
156+
if (replaceFile === undefined) {
157+
replaceFile = match[1] + ".js";
158+
}
159+
160+
return matchStr.replace(match[1], replaceFile);
161+
162+
// return ` from '${replaceFile}'`;
163+
};
164+
// Add file extensions to imports:
165+
fileContent = await customReplaceAll(
166+
fileContent,
167+
/ from '(.*?)'/g,
168+
maybeReplaceCb
169+
);
170+
171+
fileContent = await customReplaceAll(
172+
fileContent,
173+
/import '(.*?)'/g,
174+
maybeReplaceCb
175+
);
176+
177+
// myFunction && myFunction() -> myFunction?.()
178+
fileContent = await customReplaceAll(
179+
fileContent,
180+
/([^ \n\t]+) && ([^ \n\t]+)\(/g,
181+
(match) => {
182+
if (match[1] !== match[2]) return undefined;
183+
184+
return `${match[1]}?.(`;
185+
}
186+
);
187+
188+
// Custom fixes:
189+
fileContent = fileContent
190+
191+
// import deepmerge from 'deepmerge'
192+
//
193+
.replaceAll(
194+
/import (\w+) = require\('([\w-]+)'\)/g, // `import _ = require('underscore')`,
195+
`import $1 from '$2'` // `import _ from 'underscore'`
196+
)
197+
.replaceAll(
198+
`import deepmerge = require('deepmerge')`,
199+
`import deepmerge from 'deepmerge'`
200+
)
201+
.replaceAll(
202+
/const (\w+) = require\('([\w-]+)'\)\n/g, //`const clone = require('fast-clone')`,
203+
`import $1 from '$2'\n` // `import clone from 'fast-clone'`
204+
)
205+
.replaceAll(
206+
`import * as deepExtend from 'deep-extend'`,
207+
`import deepExtend from 'deep-extend'`
208+
)
209+
.replaceAll(
210+
`import * as deepmerge from 'deepmerge'`,
211+
`import deepmerge from 'deepmerge'`
212+
)
213+
.replaceAll(
214+
`import * as EventEmitter from 'events'`,
215+
`import { EventEmitter } from 'events'`
216+
)
217+
.replaceAll(
218+
`import objectPath from 'object-path'`,
219+
`import * as objectPath from 'object-path'`
220+
)
221+
.replaceAll(
222+
`import * as _ from 'underscore'`,
223+
`import _ from 'underscore'`
224+
)
225+
226+
.replaceAll(
227+
`// eslint-disable-next-line no-process-exit`,
228+
`// eslint-disable-next-line n/no-process-exit`
229+
)
230+
.replaceAll(
231+
`// eslint-disable-next-line @typescript-eslint/ban-types`,
232+
`// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type`
233+
)
234+
.replaceAll(
235+
`// eslint-disable-next-line @typescript-eslint/no-empty-interface`,
236+
`// eslint-disable-next-line @typescript-eslint/no-empty-object-type`
237+
);
238+
239+
if (fileContentOrg !== fileContent) {
240+
modified.push(filename);
241+
if (writeChanges) await fs.writeFile(filePath, fileContent, "utf-8");
242+
else console.log(`Needs fixing: ${filename}`);
243+
}
244+
}
245+
if (writeChanges) {
246+
console.log(`Modified ${modified.length} files`);
247+
} else {
248+
if (modified.length > 0) {
249+
throw new Error(`${modified.length} files need fixing`);
250+
} else {
251+
console.log(
252+
`${modified.length} files need fixing (checked ${files.length} files)`
253+
);
254+
}
255+
}
256+
}
257+
async function runCmd(cmd) {
258+
await new Promise((resolve, reject) => {
259+
const child = cp.exec(cmd, (err, stdout, stderr) => {
260+
if (err) {
261+
// console.error("stderr", stderr);
262+
reject(err);
263+
} else {
264+
resolve(stdout);
265+
}
266+
});
267+
268+
child.stdout.pipe(process.stdout);
269+
child.stderr.pipe(process.stderr);
270+
});
271+
}
272+
async function customReplaceAll(str, regexp, cb) {
273+
const matches = str.matchAll(regexp);
274+
275+
for (const match of matches) {
276+
const replaceWith = await cb(match);
277+
if (replaceWith !== undefined) {
278+
const matchStr = match[0];
279+
280+
const newStr = str.replace(matchStr, replaceWith);
281+
282+
if (newStr !== str) {
283+
str = newStr;
284+
285+
if (!writeChanges) {
286+
console.log(`- ${matchStr}\n+ ${replaceWith}\n`);
287+
}
288+
}
289+
}
290+
}
291+
return str;
292+
}
293+
294+
const cache = new Map();
295+
async function isDirectory(filePath) {
296+
if (cache.has(filePath)) return cache.get(filePath);
297+
298+
const stats = await fs.stat(filePath);
299+
const isDir = stats.isDirectory();
300+
301+
cache.set(filePath, isDir);
302+
return isDir;
303+
}
304+
async function fsExists(filePath) {
305+
try {
306+
await fs.access(filePath);
307+
return true;
308+
} catch (e) {
309+
return false;
310+
}
311+
}
312+
313+
main()
314+
.catch(console.error)
315+
.then(() => process.exit(exitCode));

0 commit comments

Comments
 (0)