-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathtypescript-autofix-js-import-extension.js
152 lines (107 loc) · 3.36 KB
/
typescript-autofix-js-import-extension.js
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
/*
typescript: autofix js import extension
parse the output of tsc for "Did you mean" suggestions
and autofix the typescript source files
why
node 19 has removed the --experimental-specifier-resolution flag
so we cannot call
node --experimental-specifier-resolution=node index.js
to import files without file extension
we could use custom loaders like
node --loader=some/where.js index.js
but adding the ".js" file extension is a simpler fix
usage
update your tsconfig.json to produce error TS2835
"Relative import paths need explicit file extensions in EcmaScript imports"
{
"compilerOptions": {
"moduleResolution": "nodeNext",
},
}
run tsc, save output to a logfile
npx tsc | tee tsc.log
or
npm run build | tee tsc.log
run this script
cat tsc.log | node typescript-autofix-js-import-extension.js
check the "patching file" output
if it looks good, run this script again with '-w'
cat tsc.log | node typescript-autofix-js-import-extension.js -w
similar tools
https://www.npmjs.com/package/@digitak/tsc-esm
https://github.com/Zoltu/typescript-transformer-append-js-extension
https://gist.github.com/weswigham/f477373b6124cc43df5356c75f66911b
related issues
https://github.com/microsoft/TypeScript/issues/19255
https://github.com/microsoft/TypeScript/issues/16577
license: MIT
*/
/*
const readline = require('readline');
const fs = require('fs');
const process = require('process');
*/
import readline from 'readline';
import fs from 'fs';
import process from 'process';
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
rl.on('line', (logLine) => {
//console.log(logLine);
const match = logLine.match(/^(.*?\.(ts|tsx))\((\d+),(\d+)\): error (TS\d+): (.*)$/)
if (!match) {
console.log(`ignoring line: ${logLine}`)
return
}
const [_, file, _ext, lineNum, columnNum, err, msg] = match
const lineIdx = +lineNum - 1
const columnIdx = +columnNum - 1
if (err == "TS2835") {
// Relative import paths need explicit file extensions in EcmaScript imports
// when '--moduleResolution' is 'node16' or 'nodenext'.
// Did you mean './path/to/file.js'?
const fixedImport = (msg.match(/Did you mean '(.*)'\?$/) || [])[1]
if (!fixedImport) {
console.log(`no fixedImport in line: ${logLine}`)
return
}
// only fix relative imports
// todo: fix module file imports like "some-module/lib/some-file"
if (!(
fixedImport.startsWith("./") ||
fixedImport.startsWith("../")
)) {
return
}
const badImport = fixedImport.slice(0, -3) // remove .js extension
const src = fs.readFileSync(file, "utf8")
const lines = src.split("\n")
const line = lines[lineIdx]
//const string = line.slice(columnIdx)
const quote = line[columnIdx]
const fixedLine = line.replace(
quote + badImport + quote,
quote + fixedImport + quote
)
if (line == fixedLine) {
return
}
lines[lineIdx] = fixedLine
console.log(`patching file: ${file}:\n - ${line}\n + ${fixedLine}`)
if (process.argv.includes("-w")) {
// write file
fs.writeFileSync(file, lines.join("\n"), "utf8")
}
return
}
console.log(logLine);
});
rl.once('close', () => {
// end of input
if (!process.argv.includes("-w")) {
console.log("done. run this script with argument '-w' to write files");
}
});