Skip to content

Commit 4b12932

Browse files
committed
fix: eslint fix files in memory in case of non-existing files
1 parent 0514d10 commit 4b12932

File tree

1 file changed

+70
-21
lines changed

1 file changed

+70
-21
lines changed

src/utils/postprocess-files.ts

Lines changed: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import path from 'path';
1+
import fs from 'node:fs/promises';
2+
import path from 'node:path';
23
import type {ESLint as ESLintClass} from 'eslint';
34
import {
45
ClientGenerationResultFile,
@@ -15,29 +16,77 @@ export async function postprocessFiles({
1516
outputDirPath: string;
1617
}): Promise<ClientGenerationResultFile[]> {
1718
if (enableEslint) {
18-
// This is an optional dependency, so we require it here to avoid loading it when it's not needed.
19-
// eslint-disable-next-line @typescript-eslint/no-var-requires
20-
const {ESLint} = require('eslint') as {ESLint: typeof ESLintClass};
21-
const eslint = new ESLint({
22-
fix: true
23-
});
19+
// TypeScript parser expects files to be present, so we need to create directories for them.
20+
const directoriesToRemove: string[] = [];
21+
const directories: Set<string> = new Set();
22+
for (const file of files) {
23+
const directory = path.dirname(path.resolve(outputDirPath, file.filename));
24+
directories.add(directory);
25+
}
2426

25-
return Promise.all(
26-
files.map(async (file) => {
27-
const [result] = await eslint.lintText(file.data, {
28-
filePath: path.resolve(outputDirPath, file.filename)
29-
});
30-
for (const message of result.messages) {
31-
if (message.fatal) {
32-
throw new Error(`Fatal ESLint error in ${file.filename}: ${message.message}`);
27+
for (const directory of Array.from(directories)) {
28+
try {
29+
await fs.stat(directory);
30+
} catch (_e) {
31+
const directoryBits = directory.split(path.sep);
32+
let currentDirectory = directoryBits.shift() || '/';
33+
for (;;) {
34+
try {
35+
await fs.stat(currentDirectory);
36+
} catch (e) {
37+
await fs.mkdir(currentDirectory);
38+
directoriesToRemove.unshift(currentDirectory);
3339
}
40+
const subDirectory = directoryBits.shift();
41+
if (!subDirectory) {
42+
break;
43+
}
44+
currentDirectory = path.join(currentDirectory, subDirectory);
3445
}
35-
return {
36-
...file,
37-
data: result.output ?? file.data
38-
};
39-
})
40-
);
46+
}
47+
}
48+
49+
try {
50+
// This is an optional dependency, so we require it here to avoid loading it when it's not needed.
51+
// eslint-disable-next-line @typescript-eslint/no-var-requires
52+
const {ESLint} = require('eslint') as {ESLint: typeof ESLintClass};
53+
const eslint = new ESLint({
54+
fix: true
55+
});
56+
57+
return await Promise.all(
58+
files.map(async (file) => {
59+
const filePath = path.resolve(outputDirPath, file.filename);
60+
let fileCreated = false;
61+
try {
62+
try {
63+
await fs.stat(filePath);
64+
} catch (_e) {
65+
await fs.writeFile(filePath, file.data);
66+
fileCreated = true;
67+
}
68+
const [result] = await eslint.lintText(file.data, {filePath});
69+
for (const message of result.messages) {
70+
if (message.fatal) {
71+
throw new Error(`Fatal ESLint error in ${file.filename}: ${message.message}`);
72+
}
73+
}
74+
return {
75+
...file,
76+
data: result.output ?? file.data
77+
};
78+
} finally {
79+
if (fileCreated) {
80+
await fs.unlink(filePath);
81+
}
82+
}
83+
})
84+
);
85+
} finally {
86+
for (const directory of directoriesToRemove) {
87+
await fs.rmdir(directory);
88+
}
89+
}
4190
}
4291
return files;
4392
}

0 commit comments

Comments
 (0)