Upgrade typescript to v5.5 (#16388)

This commit is contained in:
fisker Cheung authored and GitHub committed 2024-06-13 09:13:41 +08:00
1 parent 32c4cd3fdb
commit 3f5a4c9fe5
9 files changed
+1249 -75

No files matched your search

+14
View File
@@ -54,6 +54,20 @@ function getEsbuildOptions({ file, files, shouldCollectLicenses, cliOptions }) {
module: "*",
process: transform,
},
// Transform `require("typescript")` to `import`
{
module: "*",
process(text, file) {
text = text.replaceAll(
/(?:const|let|var) (\w+) = (?:__importStar\(require\("typescript"\)\)|require\("typescript"\));/g,
'import * as $1 from "typescript";',
);
if (/require\(["']typescript["']\)/.test(text)) {
throw new Error(`Unexpected \`require("typescript")\` in ${file}.`);
}
return text;
},
},
// #12493, not sure what the problem is, but replace the cjs version with esm version seems fix it
{
module: require.resolve("tslib"),
+16 -1
View File
@@ -133,7 +133,11 @@ const pluginFiles = [
.replace('require("./create-program/createDefaultProgram")', "{}")
.replace('require("./create-program/createIsolatedProgram")', "{}")
.replace('require("./create-program/createProjectProgram")', "{}")
.replace('require("./create-program/useProvidedPrograms")', "{}");
.replace('require("./create-program/useProvidedPrograms")', "{}")
.replace(
'require("./semantic-or-syntactic-errors")',
"{getFirstSemanticOrSyntacticError(){}}",
);
return text;
},
},
@@ -266,6 +270,17 @@ const pluginFiles = [
return text;
},
},
// Use named import from `typescript`
{
module: getPackageFile("ts-api-utils/lib/index.js"),
process(text) {
text = text.replaceAll(
/(?<=import )(?=\w+ from ["']typescript["'])/g,
"* as ",
);
return text;
},
},
],
},
{
+129 -63
View File
@@ -5,9 +5,10 @@ import MagicString from "magic-string";
import { outdent } from "outdent";
import { PROJECT_ROOT, writeFile } from "../utils/index.js";
import UNUSED_SPECIFIERS from "./typescript-unused-specifiers.js";
function* getModules(text) {
const parts = text.split(/(?<=\n)( {2}\/\/ src\/\S+\n)/);
const parts = text.split(/(?<=\n)(\/\/ src\/\S+\n)/);
let start = parts[0].length;
@@ -15,31 +16,16 @@ function* getModules(text) {
const comment = parts[partIndex];
const code = parts[partIndex + 1];
const path = comment.slice(" // ".length, -1);
const path = comment.slice("// ".length, -1);
const end = start + comment.length + code.length;
if (/\S/.test(code)) {
const esmRegExp = new RegExp(
[
String.raw`\s*var (?<initFunctionName>\w+) = __esm\({`,
`\\s*"${escapeStringRegexp(path)}"\\(\\) {`,
".*",
String.raw`\s*}`,
String.raw`\s*}\);`,
].join(String.raw`\n`),
"s",
);
const match = code.match(esmRegExp);
yield {
isEntry: path === "src/typescript/typescript.ts",
path,
start: start + comment.length,
end: end - 1,
code,
esmModuleInitFunctionName: match?.groups.initFunctionName,
};
}
yield {
isEntry: path === "src/typescript/typescript.ts",
path,
start: start + comment.length,
end: end - 1,
code,
};
start = end;
}
@@ -65,16 +51,7 @@ class TypeScriptModuleSource {
module = found;
}
const { esmModuleInitFunctionName } = module;
const moduleInitCode = esmModuleInitFunctionName
? `var ${esmModuleInitFunctionName} = () => {};`
: "";
this.#source.overwrite(
module.start,
module.end,
moduleInitCode + replacement,
);
this.#source.overwrite(module.start, module.end, replacement);
return this;
}
@@ -142,8 +119,8 @@ class TypeScriptModuleSource {
}
function unwrap(text) {
const startMark = "var ts = (() => {";
const endMark = "return require_typescript();";
const startMark = 'var ts = {}; ((module) => {\n"use strict";';
const endMark = "// src/typescript/typescript.ts";
const start = text.indexOf(startMark);
const end = text.lastIndexOf(endMark);
@@ -151,7 +128,40 @@ function unwrap(text) {
throw new Error("Unexpected source");
}
return text.slice(start + startMark.length, end);
text = text.slice(start + startMark.length, end);
return text;
}
function getExports(entry) {
let lines = entry.code.trim().split("\n");
if (
!(
lines[0] === "var typescript_exports = {};" &&
lines[1] === "__export(typescript_exports, {" &&
lines.at(-2) === "});" &&
lines.at(-1) === "module.exports = __toCommonJS(typescript_exports);"
)
) {
throw new Error("Unexpected source");
}
lines = lines.slice(2, -2);
const exports = lines.map((line) => {
const match = line.match(
/^\s*(?<specifier>.*?): \(\) => (?<variable>.*?),?$/,
);
if (!match) {
throw new Error("Unexpected source");
}
return match.groups;
});
return exports;
}
function modifyTypescriptModule(text) {
@@ -159,6 +169,21 @@ function modifyTypescriptModule(text) {
const source = new TypeScriptModuleSource(text);
const entry = source.modules.find((module) => module.isEntry);
let exports = getExports(entry);
source.removeModule(entry);
// print variables from core.ts to ignore
// const coreModule = source.modules.find(
// (module) => module.path === "src/compiler/core.ts",
// );
// const variables = [
// ...coreModule.code.matchAll(/(?<=\n)var (?<variable>\w+) =/g),
// ...coreModule.code.matchAll(/(?<=\n)function (?<variable>\w+)\(/g),
// ].map((match) => match.groups.variable);
// console.log(JSON.stringify(variables, undefined, 2));
// Deprecated
for (const module of source.modules) {
if (module.path.startsWith("src/deprecatedCompat/")) {
@@ -175,10 +200,7 @@ function modifyTypescriptModule(text) {
// services
for (const module of source.modules) {
if (
module.path === "src/services/services.ts" ||
module.path === "src/services/_namespaces/ts.ts"
) {
if (module.path === "src/services/services.ts") {
continue;
}
@@ -186,13 +208,7 @@ function modifyTypescriptModule(text) {
if (module.path === "src/services/utilities.ts") {
source.replaceModule(
module,
outdent`
var scanner;
var ${module.esmModuleInitFunctionName} = () => {
init_debug();
scanner = createScanner(99 /* Latest */, /*skipTrivia*/ true);
};
`,
"var scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true);",
);
continue;
}
@@ -203,6 +219,7 @@ function modifyTypescriptModule(text) {
}
// server
source.removeModule("src/typescript/_namespaces/ts.server.ts");
for (const module of source.modules) {
if (module.path.startsWith("src/server/")) {
source.removeModule(module);
@@ -217,6 +234,13 @@ function modifyTypescriptModule(text) {
}
}
// `typingsInstaller`
for (const module of source.modules) {
if (module.path.startsWith("src/typingsInstallerCore/")) {
source.removeModule(module);
}
}
// `ts.moduleSpecifiers`
source.removeModule("src/compiler/_namespaces/ts.moduleSpecifiers.ts");
source.removeModule("src/compiler/moduleSpecifiers.ts");
@@ -237,7 +261,6 @@ function modifyTypescriptModule(text) {
source.removeModule("src/compiler/tsbuild.ts");
source.removeModule("src/compiler/tsbuildPublic.ts");
source.removeModule("src/compiler/builderState.ts");
source.removeModule("src/compiler/builderStatePublic.ts");
// Misc
source.removeModule("src/compiler/symbolWalker.ts");
@@ -249,6 +272,8 @@ function modifyTypescriptModule(text) {
source.removeModule("src/compiler/visitorPublic.ts");
source.removeModule("src/compiler/emitter.ts");
source.removeModule("src/compiler/_namespaces/ts.performance.ts");
source.removeModule("src/compiler/executeCommandLine.ts");
source.removeModule("src/compiler/expressionToTypeNode.ts");
// File system
source.replaceModule("src/compiler/sys.ts", "var sys;");
@@ -260,7 +285,7 @@ function modifyTypescriptModule(text) {
"var perfLogger = new Proxy(() => {}, {get: () => perfLogger});",
);
// performanceCore
// performance
source.replaceModule(
"src/compiler/performanceCore.ts",
outdent`
@@ -268,21 +293,32 @@ function modifyTypescriptModule(text) {
var timestamp = Date.now;
`,
);
source.replaceModule(
"src/compiler/performance.ts",
outdent`
var mark = () => {};
var measure = () => {};
`,
);
// `factory`
source.removeModule("src/compiler/factory/emitNode.ts");
source.removeModule("src/compiler/factory/emitHelpers.ts");
source.replaceModule(
"src/compiler/factory/nodeConverters.ts",
outdent`
var createNodeConverters = () => new Proxy({}, {get: () => () => {}});
`,
);
source.removeModule("src/compiler/factory/nodeConverters.ts");
// `pnp`
if (source.hasModule("src/compiler/pnp.ts")) {
source.removeModule("src/compiler/pnp.ts");
}
if (source.hasModule("src/compiler/pnpapi.ts")) {
source.removeModule("src/compiler/pnpapi.ts");
}
source.replaceAlignedCode({
start: "function isNodeLikeSystem(",
end: "}",
replacement: "function isNodeLikeSystem() {return false}",
});
/* spell-checker: disable */
// `ts.createParenthesizerRules`
@@ -293,8 +329,8 @@ function modifyTypescriptModule(text) {
/* spell-checker: enable */
source.replaceAlignedCode({
start: "function getScriptTargetFeatures(",
end: "}",
start: "var getScriptTargetFeatures = /* @__PURE__ */ memoize(",
end: ");",
});
source.replaceAlignedCode({
@@ -302,16 +338,46 @@ function modifyTypescriptModule(text) {
end: "});",
});
source.append("module.exports = require_typescript();");
let code = source.toString();
exports = exports.filter(
({ specifier }) => !UNUSED_SPECIFIERS.has(specifier),
);
return source.toString();
code = addExports(code, exports);
code +=
"\n" +
outdent`
export const isUnparsedPrepend = () => false;
export const isUnparsedTextLike = () => false;
`;
return { code, exports };
}
function addExports(code, exports) {
return (
code +
"\n\n" +
outdent`
export {
${exports
.map(({ specifier, variable }) =>
variable === specifier ? specifier : `${variable} as ${specifier}`,
)
.map((line) => ` ${line},`)
.join("\n")}
};
`
);
}
// Save modified code to `{PROJECT_ROOT}/.tmp/modified-typescript.js` for debug
const saveOutputToDisk = (process) => (text) => {
const result = process(text);
writeFile(path.join(PROJECT_ROOT, ".tmp/modified-typescript.js"), result);
return result;
const { code } = process(text);
writeFile(path.join(PROJECT_ROOT, ".tmp/modified-typescript.js"), code);
return code;
};
export default saveOutputToDisk(modifyTypescriptModule);
export { modifyTypescriptModule };
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,63 @@
import fs from "node:fs/promises";
import esbuild from "esbuild";
import * as importMetaResolve from "import-meta-resolve";
import { outdent } from "outdent";
import * as prettier from "prettier";
import * as typescript from "typescript";
import { modifyTypescriptModule } from "./build/modify-typescript-module.js";
import UNUSED_SPECIFIERS from "./build/typescript-unused-specifiers.js";
async function getRemovedSpecifiers(code, exports) {
let errors = [];
try {
await esbuild.transformSync(code, { loader: "js" });
return;
} catch (error) {
({ errors } = error);
}
const specifiers = [];
for (const { text } of errors) {
const match = text.match(
/^"(?<variable>.*?)" is not declared in this file$/,
);
if (match) {
const { specifier } = exports.find(
({ variable }) => variable === match.groups.variable,
);
specifiers.push(specifier);
}
}
return specifiers;
}
async function main() {
const original = await fs.readFile(
new URL(importMetaResolve.resolve("typescript", import.meta.url)),
"utf8",
);
const { code, exports } = modifyTypescriptModule(original);
let specifiers = (await getRemovedSpecifiers(code, exports)) ?? [];
specifiers = [...new Set([...UNUSED_SPECIFIERS, ...specifiers])]
.filter((specifier) => Object.hasOwn(typescript, specifier))
.sort();
await fs.writeFile(
new URL("./build/typescript-unused-specifiers.js", import.meta.url),
await prettier.format(
outdent`
export default new Set(${JSON.stringify(specifiers, undefined, 2)});
`,
{ parser: "meriyah" },
),
);
console.log("typescript-unused-specifiers.js updated.");
}
await main();