Files
test-repo/scripts/build/modify-typescript-module.mjs
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

591 lines
16 KiB
JavaScript
Raw Normal View History

import path from "node:path";
import escapeStringRegexp from "escape-string-regexp";
import { outdent } from "outdent";
2022-09-22 19:11:19 +08:00
import MagicString from "magic-string";
import { writeFile, PROJECT_ROOT } from "../utils/index.mjs";
/*
Root submodule in `typescript.js` are bundled like
```js
var ts;
(function (ts) {
// Submodule
})(ts || (ts = {}));
```
*/
const SUBMODULE_START = escapeStringRegexp("var ts;\n(function (ts) {");
const SUBMODULE_END = escapeStringRegexp("})(ts || (ts = {}));");
2022-09-22 19:11:19 +08:00
function getSubmodules(text) {
const regexp = new RegExp(
[
"(?<=\n)",
`(?<before>${SUBMODULE_START})`,
"(?=\n)",
"(?<text>.*?)",
"(?<=\n)",
`(?<after>${SUBMODULE_END})`,
"(?=\n)",
].join(""),
"gsu"
);
2022-09-22 19:11:19 +08:00
return [...text.matchAll(regexp)].map((match) => ({
start: match.index,
end: match.index + match[0].length,
...match.groups,
}));
}
2022-09-22 19:11:19 +08:00
class TypeScriptModuleSource {
#source;
#modules;
2022-09-22 19:11:19 +08:00
constructor(text) {
this.#source = new MagicString(text);
this.#modules = getSubmodules(text);
}
2022-09-22 19:11:19 +08:00
removeSubmodule(testFunction) {
return this.replaceSubmodule(testFunction, "");
}
2022-09-22 19:11:19 +08:00
replaceSubmodule(testFunction, replacement) {
const modules = this.#modules.filter(({ text }) => testFunction(text));
if (modules.length !== 1) {
2022-09-22 19:17:55 +08:00
throw Object.assign(
new Error(
`Expect exactly one submodule to be found, got ${modules.length} submodules.`
),
{ modules }
);
2022-09-22 19:11:19 +08:00
}
2022-09-22 19:11:19 +08:00
const [{ start, end, before, after }] = modules;
if (!replacement) {
this.#source.remove(start, end);
} else {
this.#source.overwrite(
start,
end,
before + "\n" + replacement + "\n" + after
);
}
return this;
}
2022-09-22 19:11:19 +08:00
removeMultipleSubmodules(testFunction) {
const modules = this.#modules.filter(({ text }) => testFunction(text));
if (modules.length < 2) {
throw new Error("Expect more than one submodules to be found");
}
for (const { start, end } of modules) {
this.#source.remove(start, end);
}
return this;
}
2022-09-22 19:11:19 +08:00
replaceAlignedCode({ start, end, replacement = "" }) {
const regexp = new RegExp(
[
"(?<=\n)",
"(?<indentString>\\s*)",
escapeStringRegexp(start),
".*?",
"(?<=\n)",
"\\k<indentString>",
escapeStringRegexp(end),
"(?=\n)",
].join(""),
"gsu"
);
2022-09-22 19:11:19 +08:00
this.#source.replaceAll(regexp, replacement);
return this;
}
2022-09-22 19:11:19 +08:00
remove(...args) {
this.#source.remove(...args);
return this;
}
2022-09-22 19:11:19 +08:00
append(...args) {
this.#source.append(...args);
return this;
}
2022-10-26 10:02:23 +08:00
replace(...args) {
this.#source.replace(...args);
return this;
}
2022-09-22 19:11:19 +08:00
replaceAll(...args) {
this.#source.replaceAll(...args);
return this;
}
2022-09-22 20:20:16 +08:00
applyChanges() {
const text = this.#source.toString();
this.#source = new MagicString(text);
this.#modules = getSubmodules(text);
}
2022-09-22 19:11:19 +08:00
toString() {
return this.#source.toString();
}
}
function modifyTypescriptModule(text) {
2022-09-22 19:11:19 +08:00
const source = new TypeScriptModuleSource(text);
// Code after `globalThis` shim are useless
const positionOfGlobalThisShim = text.indexOf(
"// We polyfill `globalThis` here so re can reliably patch the global scope"
);
if (positionOfGlobalThisShim === -1) {
throw new Error("Unexpected source.");
}
2022-09-22 19:11:19 +08:00
source.remove(positionOfGlobalThisShim, text.length);
source.append("module.exports = ts;");
2022-10-26 10:02:23 +08:00
// `Map`/`Set` shim
source.removeSubmodule((text) =>
text.includes("ShimCollections = ts.ShimCollections")
);
// File system
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("ts.generateDjb2Hash = generateDjb2Hash;")
);
// Language service
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("ts.TypeScriptServicesFactory = TypeScriptServicesFactory;")
);
2022-10-26 10:02:23 +08:00
source
.replaceAlignedCode({
start: "function createLanguageService(",
end: "}",
})
.replace("ts.createLanguageService = createLanguageService;", "");
2022-10-26 20:34:47 +08:00
// `ts.scanner`
// This is a big module, most code except `ts.scanner` is not used
source.replaceSubmodule(
(text) => text.includes("ts.findPackageJson = findPackageJson;"),
"ts.scanner = ts.createScanner(99 /* ScriptTarget.Latest */, /*skipTrivia*/ true);"
);
// `ts.visitNode`
source.removeSubmodule((text) => text.includes("ts.visitNode = visitNode;"));
// `ts.createGetSymbolWalker`
source.removeSubmodule((text) =>
text.includes("ts.createGetSymbolWalker = createGetSymbolWalker;")
);
// `ts.getModuleInstanceState `
source.removeSubmodule((text) =>
text.includes("ts.getModuleInstanceState = getModuleInstanceState;")
);
2022-10-26 10:02:23 +08:00
/* spell-checker: disable */
// `ts.createParenthesizerRules`
source
.replaceAlignedCode({
start: "function createParenthesizerRules(",
end: "}",
})
.replace(
"ts.createParenthesizerRules = createParenthesizerRules;",
"ts.createParenthesizerRules = () => ts.nullParenthesizerRules;"
);
/* spell-checker: enable */
// `ts.createNodeConverters`
source
.replaceAlignedCode({
start: "function createNodeConverters(",
end: "}",
})
.replace(
"ts.createNodeConverters = createNodeConverters;",
"ts.createNodeConverters = () => ts.nullNodeConverters;"
);
2022-10-26 20:34:47 +08:00
// `ts.classifier`
source.removeSubmodule((text) => text.includes("classifier = ts.classifier"));
source.removeSubmodule((text) =>
text.includes("ts.createClassifier = createClassifier;")
);
2022-10-26 10:02:23 +08:00
// `ts.getScriptTargetFeatures`
source
.replaceAlignedCode({
start: "function getScriptTargetFeatures(",
end: "}",
})
.replace("ts.getScriptTargetFeatures = getScriptTargetFeatures;", "");
// `ts.Version`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) => text.includes("ts.Version = Version;"));
// `ts.transform`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) => text.includes("ts.transform = transform;"));
2022-10-26 10:02:23 +08:00
source.removeSubmodule((text) =>
text.includes("ts.getOrCreateEmitNode = getOrCreateEmitNode;")
);
source.removeSubmodule((text) =>
text.includes("ts.createEmitHelperFactory = createEmitHelperFactory;")
);
// `ts.BreakpointResolver`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.trimStart().startsWith("var BreakpointResolver;")
);
// `ts.textChanges`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.trimStart().startsWith("var textChanges;")
);
// `ts.preProcessFile`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("ts.preProcessFile = preProcessFile;")
);
// `ts.Rename`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) => text.trimStart().startsWith("var Rename;"));
// `ts.SmartSelectionRange`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.trimStart().startsWith("var SmartSelectionRange;")
);
// `ts.SignatureHelp`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.trimStart().startsWith("var SignatureHelp;")
);
// `ts.InlayHints`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.trimStart().startsWith("var InlayHints;")
);
// Sourcemap
2022-09-22 19:11:19 +08:00
source
.removeSubmodule((text) =>
text.includes("ts.getSourceMapper = getSourceMapper;")
)
.removeSubmodule((text) =>
text.includes("ts.createSourceMapGenerator = createSourceMapGenerator;")
);
// Suggestion
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes(
"ts.computeSuggestionDiagnostics = computeSuggestionDiagnostics;"
)
);
// Tracing
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("ts.startTracing = tracingEnabled.startTracing;")
);
// Diagnostics
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("ts.createProgramHost = createProgramHost;")
);
// `ts.transformTypeScript`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("ts.transformTypeScript = transformTypeScript;")
);
// `ts.createRuntimeTypeSerializer`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes(
"ts.createRuntimeTypeSerializer = createRuntimeTypeSerializer;"
)
);
// Transform
2022-09-22 19:11:19 +08:00
source
// `ts.transformLegacyDecorators`
.removeSubmodule((text) =>
text.includes("ts.transformLegacyDecorators = transformLegacyDecorators;")
)
// `ts.transformES5`
.removeSubmodule((text) => text.includes("ts.transformES5 = transformES5;"))
// `ts.transformES2015`
.removeSubmodule((text) =>
text.includes("ts.transformES2015 = transformES2015;")
)
// `ts.transformES2016`
.removeSubmodule((text) =>
text.includes("ts.transformES2016 = transformES2016;")
)
// `ts.transformES2017` & `ts.createSuperAccessVariableStatement`
.removeSubmodule(
(text) =>
text.includes("ts.transformES2017 = transformES2017;") &&
text.includes(
"ts.createSuperAccessVariableStatement = createSuperAccessVariableStatement;"
)
)
// `ts.transformES2018`
.removeSubmodule((text) =>
text.includes("ts.transformES2018 = transformES2018;")
)
// `ts.transformES2019`
.removeSubmodule((text) =>
text.includes("ts.transformES2019 = transformES2019;")
)
// `ts.transformES2020`
.removeSubmodule((text) =>
text.includes("ts.transformES2020 = transformES2020;")
)
// `ts.transformES2021`
.removeSubmodule((text) =>
text.includes("ts.transformES2021 = transformES2021;")
)
// `ts.transformESNext`
.removeSubmodule((text) =>
text.includes("ts.transformESNext = transformESNext;")
)
// `ts.transformJsx`
.removeSubmodule((text) => text.includes("ts.transformJsx = transformJsx;"))
// `ts.transformGenerators`
.removeSubmodule((text) =>
text.includes("ts.transformGenerators = transformGenerators;")
)
// `ts.transformModule`
.removeSubmodule((text) =>
text.includes("ts.transformModule = transformModule;")
)
// `ts.transformSystemModule`
.removeSubmodule((text) =>
text.includes("ts.transformSystemModule = transformSystemModule;")
)
// `ts.transformECMAScriptModule`
.removeSubmodule((text) =>
text.includes("ts.transformECMAScriptModule = transformECMAScriptModule;")
)
// `ts.transformNodeModule`
.removeSubmodule((text) =>
text.includes("ts.transformNodeModule = transformNodeModule;")
)
// `ts.transformClassFields`
.removeSubmodule((text) =>
text.includes("ts.transformClassFields = transformClassFields;")
)
// `ts.transformDeclarations`
.removeSubmodule((text) =>
text.includes("ts.transformDeclarations = transformDeclarations;")
);
// `ts.transformNodes` and more
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("ts.transformNodes = transformNodes;")
);
// `ts.server`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) => text.includes("(ts.server = {})"));
// `ts.JsTyping`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) => text.includes("(ts.JsTyping = {})"));
// `ts.ClassificationType`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("(ts.ClassificationType = {})")
);
// Build
2022-09-22 19:11:19 +08:00
source
.removeSubmodule((text) =>
text.includes("ts.createSolutionBuilder = createSolutionBuilder;")
)
2022-09-22 19:11:19 +08:00
.removeSubmodule((text) =>
text.includes("ts.parseBuildCommand = parseBuildCommand;")
)
2022-09-22 19:11:19 +08:00
.removeSubmodule((text) =>
text.includes("ts.createBuilderProgram = createBuilderProgram;")
)
.removeSubmodule((text) =>
text.includes(
"ts.createSemanticDiagnosticsBuilderProgram = createSemanticDiagnosticsBuilderProgram;"
)
)
.removeSubmodule((text) =>
text.includes("ts.createResolutionCache = createResolutionCache;")
)
.removeSubmodule((text) =>
text.includes("ts.createWatchCompilerHost = createWatchCompilerHost;")
)
.removeSubmodule((text) =>
text.includes(
"ts.resolveConfigFileProjectName = resolveConfigFileProjectName;"
)
)
.removeSubmodule((text) =>
text.includes("ts.getBuildInfo = getBuildInfo;")
);
// Compile
2022-09-22 19:11:19 +08:00
source
.removeSubmodule((text) =>
text.includes("ts.createCompilerHost = createCompilerHost;")
)
.removeSubmodule((text) => text.includes("(ts.BuilderState = {})"))
.removeSubmodule((text) => text.includes("ts.transpile = transpile;"));
// Watch
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("ts.getWatchFactory = getWatchFactory;")
);
2022-10-10 20:28:54 +08:00
// `import`/`export` cache
source.removeSubmodule((text) =>
text.includes(
/* cspell:disable-next-line */
"ts.createCacheableExportInfoMap = createCacheableExportInfoMap;"
)
);
// `ts.canProduceDiagnostics`, `ts.createGetSymbolAccessibilityDiagnosticForNode`, and `ts.createGetSymbolAccessibilityDiagnosticForNode`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("ts.canProduceDiagnostics = canProduceDiagnostics;")
);
// `ts.moduleSpecifiers`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) => text.includes("(ts.moduleSpecifiers = {})"));
// `ts.trace`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) => text.includes("ts.trace = trace;"));
// `ts.createTypeChecker`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("ts.createTypeChecker = createTypeChecker;")
);
// `ts.DocumentHighlights`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("(ts.DocumentHighlights = {})")
);
// `ts.createDocumentRegistry`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes("ts.createDocumentRegistry = createDocumentRegistry;")
);
// `ts.CallHierarchy`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) => text.includes("(ts.CallHierarchy = {})"));
// `ts.flattenDestructuringAssignment` and `ts.flattenDestructuringBinding`
2022-09-22 19:11:19 +08:00
source.removeSubmodule(
(text) =>
text.includes(
"ts.flattenDestructuringAssignment = flattenDestructuringAssignment"
) &&
text.includes(
"ts.flattenDestructuringBinding = flattenDestructuringBinding"
)
);
// `ts.processTaggedTemplateExpression`
2022-09-22 19:11:19 +08:00
source.removeSubmodule((text) =>
text.includes(
"ts.processTaggedTemplateExpression = processTaggedTemplateExpression"
)
);
// Editor
2022-09-22 19:11:19 +08:00
source
.removeSubmodule((text) =>
text.includes("ts.getEditsForFileRename = getEditsForFileRename;")
)
.removeSubmodule((text) => text.includes("(ts.GoToDefinition = {})"))
.removeSubmodule((text) => text.includes("(ts.JsDoc = {})"))
.removeSubmodule((text) => text.includes("(ts.NavigateTo = {})"))
.removeSubmodule((text) => text.includes("(ts.NavigationBar = {})"))
.removeSubmodule((text) => text.includes("(ts.OrganizeImports = {})"))
.removeSubmodule((text) =>
text.includes("(ts.OutliningElementsCollector = {})")
)
.removeSubmodule((text) =>
text.includes("ts.createPatternMatcher = createPatternMatcher;")
)
.removeSubmodule((text) => text.includes("(ts.SymbolDisplay = {})"));
// `ts.refactor` (multiple)
2022-09-22 19:11:19 +08:00
source.removeMultipleSubmodules((text) =>
text.trimStart().startsWith("var refactor;")
);
// `ts.codefix` (multiple)
2022-09-22 19:11:19 +08:00
source.removeMultipleSubmodules((text) =>
text.trimStart().startsWith("var codefix;")
);
// `ts.formatting` (multiple)
2022-09-22 19:11:19 +08:00
source.removeMultipleSubmodules((text) =>
text.trimStart().startsWith("var formatting;")
);
// `ts.Completions` (multiple)
2022-09-22 19:11:19 +08:00
source.removeMultipleSubmodules((text) =>
text.trimStart().startsWith("var Completions;")
);
// `ts.FindAllReferences` (multiple)
2022-09-22 19:11:19 +08:00
source.removeMultipleSubmodules((text) =>
text.trimStart().startsWith("var FindAllReferences;")
);
// Performance
2022-09-22 19:11:19 +08:00
source.replaceSubmodule(
(text) =>
text.includes(
"ts.tryGetNativePerformanceHooks = tryGetNativePerformanceHooks;"
),
outdent`
ts.tryGetNativePerformanceHooks = () => {};
ts.timestamp = Date.now;
`
);
2022-09-22 20:20:16 +08:00
source.replaceAlignedCode({
start: "var debugObjectHost = (function () {",
end: "})();",
});
// TODO[@fisker]: investigate possible `magic-string` bug
source.applyChanges();
for (const [find, replacement] of Object.entries({
// yarn pnp
"process.versions.pnp": "undefined",
// Dynamic `require()`s
"ts.sys && ts.sys.require": "false",
"require(etwModulePath)": "undefined",
})) {
2022-09-22 19:11:19 +08:00
source.replaceAll(find, replacement);
}
2022-09-22 19:11:19 +08:00
return source.toString();
}
// 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;
};
export default saveOutputToDisk(modifyTypescriptModule);